mirror of
https://github.com/docker/docker-bench-security.git
synced 2025-05-15 22:25:29 +00:00
Compare commits
577 commits
Author | SHA1 | Date | |
---|---|---|---|
|
ff26d67f25 | ||
|
a18798fcfa | ||
|
5c42b8ad5f | ||
|
c4b7d36042 | ||
|
23110269a6 | ||
|
c495b3a774 | ||
|
12f085d42f | ||
|
966929427e | ||
|
5d5ca0a3da | ||
|
287fd8774b | ||
|
e081393ad7 | ||
|
820abe98c3 | ||
|
ba0b402ea5 | ||
|
684512b888 | ||
|
958f5fa6c3 | ||
|
0fd702afed | ||
|
8bbdaf6540 | ||
|
4edccd7859 | ||
|
8d97756c62 | ||
|
b6e4380937 | ||
|
7287a35a21 | ||
|
5c647c1b86 | ||
|
e680ab2465 | ||
|
ab2190819d | ||
|
b7a5284ce4 | ||
|
8da1cc26df | ||
|
9120d426ce | ||
|
26f80fb331 | ||
|
5555c37560 | ||
|
8ea918620e | ||
|
59fe573db2 | ||
|
2dfb1bac51 | ||
|
223baf94d1 | ||
|
d9f1d02102 | ||
|
bfbeda9263 | ||
|
1f9933a867 | ||
|
d6005f0211 | ||
|
26dc83ed28 | ||
|
2647070692 | ||
|
1d29a1f405 | ||
|
523556b4ac | ||
|
79407ce361 | ||
|
39963dad60 | ||
|
0dc2d2b1e6 | ||
|
412f514bb4 | ||
|
f97b420af9 | ||
|
c8c90ee523 | ||
|
16c235080d | ||
|
9bf4dea527 | ||
|
93227bf6c0 | ||
|
d0ccaca6a9 | ||
|
949c6a034a | ||
|
f16cd8dd62 | ||
|
6dad6fc405 | ||
|
df36db7a70 | ||
|
5a450fc5ba | ||
|
956ca6bb34 | ||
|
faa0e88479 | ||
|
41a44f54d3 | ||
|
316b610178 | ||
|
dde48fc185 | ||
|
e82fa2cf5d | ||
|
ce38d3dd3c | ||
|
cbd07bb051 | ||
|
f375045741 | ||
|
75ccbc78a3 | ||
|
941518887b | ||
|
ee718c40c0 | ||
|
5a8d6434e6 | ||
|
553c11f3a9 | ||
|
8ccd83a6f0 | ||
|
b29f676bbb | ||
|
44fdceb331 | ||
|
558fca319f | ||
|
7c7390e723 | ||
|
d4c4538bc8 | ||
|
58e732f3d1 | ||
|
bb032f154a | ||
|
cd1619c375 | ||
|
3cfa505ecc | ||
|
3fe40815ee | ||
|
d44c2a9d47 | ||
|
68c8e53dac | ||
|
715de9c607 | ||
|
975820f52b | ||
|
d33139cedc | ||
|
5c7acd72a5 | ||
|
1ff4a62836 | ||
|
0d5874877b | ||
|
3f3ff4fb2d | ||
|
0ae544dd03 | ||
|
ec211a3277 | ||
|
a409e03d99 | ||
|
7e89ea067d | ||
|
ec3ddf2acd | ||
|
fd93a6ee93 | ||
|
a40b888ee9 | ||
|
8ac4513d24 | ||
|
1891eaa8b3 | ||
|
d98a054c2f | ||
|
f656a5d683 | ||
|
e6a742ba38 | ||
|
dfb3a90f67 | ||
|
683c5a92b5 | ||
|
cf93e9ed07 | ||
|
dacc7372bf | ||
|
2024e16f09 | ||
|
e31e7aa0ae | ||
|
c6256295fc | ||
|
08a7b09d4d | ||
|
3769a64a2f | ||
|
c1457e6ad3 | ||
|
32c5e5f1fb | ||
|
4e379bbaf9 | ||
|
3a9deae328 | ||
|
bd05445528 | ||
|
28fa0393da | ||
|
6f574b07c1 | ||
|
6a685524eb | ||
|
4a4ae81a03 | ||
|
ca4ef8fa57 | ||
|
2466ab4826 | ||
|
17026093f1 | ||
|
cff5d7f32c | ||
|
addefc6ee4 | ||
|
6a8fdcf72e | ||
|
0a59baa9fb | ||
|
e4d9bd1556 | ||
|
15aa1eecd5 | ||
|
38ac7ef8d8 | ||
|
c67469d96b | ||
|
81ac358e82 | ||
|
d0443cc817 | ||
|
86985f854f | ||
|
8a934aebf1 | ||
|
4b68c2e040 | ||
|
f31e60c379 | ||
|
c8721c90fa | ||
|
68cb493117 | ||
|
cc8171fbfe | ||
|
3a7fe3bb24 | ||
|
25de0bd826 | ||
|
c05c58674a | ||
|
7e89fdd364 | ||
|
68bcd14fb3 | ||
|
e5efe2bf40 | ||
|
091b4b954a | ||
|
9722e5d89a | ||
|
7144b947de | ||
|
ca03a37db6 | ||
|
b757aa7334 | ||
|
2986d618f4 | ||
|
ee5972cb69 | ||
|
bf11d68522 | ||
|
11886d47d8 | ||
|
82ecb7e089 | ||
|
ed23f2d285 | ||
|
ad62371ace | ||
|
59a63dd49a | ||
|
c623d3afdd | ||
|
b3a36e8d94 | ||
|
82bbe1d562 | ||
|
1623c4585e | ||
|
85117ea1a2 | ||
|
f769a32e9b | ||
|
6c586b4e08 | ||
|
9ae0d92b5d | ||
|
2132b03b92 | ||
|
c00ef4330b | ||
|
58205d4ef5 | ||
|
519f20befd | ||
|
c3511209f9 | ||
|
8e0daa11de | ||
|
94900eedb9 | ||
|
1aa919e918 | ||
|
4b4fdd9f77 | ||
|
c8984e9591 | ||
|
e9b9bfd270 | ||
|
dcf478884b | ||
|
3732a475cb | ||
|
cf7c50bf33 | ||
|
7c881b4b0b | ||
|
f8c9b0fd5b | ||
|
47e4cc173c | ||
|
8bd04d683f | ||
|
d3d25c8fc8 | ||
|
f47f61538e | ||
|
75fe107048 | ||
|
b7d8805ce1 | ||
|
ca0db8898f | ||
|
1ea667f2f0 | ||
|
6ad1a1ef77 | ||
|
3877abd975 | ||
|
93c619f018 | ||
|
0f3dfe70fe | ||
|
f3e9c791ce | ||
|
d85c73316a | ||
|
919816dbbf | ||
|
b6478e9367 | ||
|
4cfb58f675 | ||
|
41593e80d0 | ||
|
b3182ca8f5 | ||
|
d6969dd2a4 | ||
|
aa984c44db | ||
|
1e0a10b71f | ||
|
8aec461d46 | ||
|
375d32c0db | ||
|
98acc66436 | ||
|
735938a8f1 | ||
|
4612146563 | ||
|
79ef925df1 | ||
|
5210cc9ff9 | ||
|
d32d4f3ce3 | ||
|
1c2b912aa2 | ||
|
d53ac42de1 | ||
|
3c38419c5b | ||
|
2cdfa3df25 | ||
|
2972b685fc | ||
|
9f92e46df8 | ||
|
51bc75eb55 | ||
|
d42fedc370 | ||
|
0307da4c61 | ||
|
b3488e7d1f | ||
|
937ec4958a | ||
|
33566331d1 | ||
|
b046f930bc | ||
|
12f19d9f64 | ||
|
e1feca8620 | ||
|
b16da2c2ed | ||
|
11da147df9 | ||
|
4054055546 | ||
|
9696a8bd6a | ||
|
685236f4e6 | ||
|
d9a70bc006 | ||
|
269b71eed8 | ||
|
19173cb954 | ||
|
c8c5615061 | ||
|
3c545daccf | ||
|
e21999c5c7 | ||
|
155c739fc9 | ||
|
f1c4dc4cd6 | ||
|
91d36b62f9 | ||
|
cf9baa76ae | ||
|
1b37a1e6bc | ||
|
c35d71f533 | ||
|
d2963b4c42 | ||
|
c2caa29512 | ||
|
b3029904d6 | ||
|
85544e1f69 | ||
|
8163884633 | ||
|
8ebf21bbc9 | ||
|
ddad135d13 | ||
|
bf42355279 | ||
|
577e9f5edb | ||
|
3bee5e6a54 | ||
|
d680213a7b | ||
|
6d73492aab | ||
|
f4e33ee54e | ||
|
b354514d29 | ||
|
59c289eefe | ||
|
d1934b614e | ||
|
3d02432bc8 | ||
|
ef206be6e0 | ||
|
e1d26673ee | ||
|
6cd952c7a1 | ||
|
c53157e184 | ||
|
7f29aebd71 | ||
|
af8b59f29d | ||
|
4bb6e19965 | ||
|
495a8674c4 | ||
|
e9d7398893 | ||
|
0cac0e339d | ||
|
c8a7e87132 | ||
|
4f3898257f | ||
|
5a829f9e8c | ||
|
77a3bc65d7 | ||
|
261e3f2611 | ||
|
71f63a192a | ||
|
7ad1c816e8 | ||
|
17c6262d2f | ||
|
d7f1d9753a | ||
|
a785c02c59 | ||
|
adb6a42c4a | ||
|
7110df800b | ||
|
bcd6e5dd55 | ||
|
ca3714bc16 | ||
|
3d6dd81956 | ||
|
0b007baf7e | ||
|
e5c22c5f01 | ||
|
f968597051 | ||
|
bb0d65ceb1 | ||
|
6c6d0836a4 | ||
|
82644982a8 | ||
|
d963b93fcc | ||
|
f2a7e6d6a6 | ||
|
28f16f0afd | ||
|
6105f02a16 | ||
|
7685c0417a | ||
|
227f2faa5b | ||
|
6720207512 | ||
|
ee9a0c5681 | ||
|
50bfd11df9 | ||
|
6e2e70da8d | ||
|
e6f1f81b7c | ||
|
972f855d42 | ||
|
ffe1d6a762 | ||
|
3f3cf01fa8 | ||
|
689c22fbeb | ||
|
e09aff559c | ||
|
e71d05de20 | ||
|
0f6c6d21a1 | ||
|
55ab78bb12 | ||
|
326e31f403 | ||
|
7aaebd63c4 | ||
|
166ccf7832 | ||
|
f791eb8a70 | ||
|
1c8699bcf3 | ||
|
2e6b7ec653 | ||
|
740439d352 | ||
|
5370aef248 | ||
|
cec124a162 | ||
|
f01acac650 | ||
|
d942b12e0a | ||
|
b802f55f1a | ||
|
689a5a62c5 | ||
|
f8be7239e5 | ||
|
7e3ecaf17d | ||
|
6d5b15788a | ||
|
a911c23915 | ||
|
2fb15f4b6d | ||
|
c560b044e4 | ||
|
b1bbe07902 | ||
|
1dd7956760 | ||
|
cc6b16d8a7 | ||
|
9d9da6d375 | ||
|
a7a24a8d7f | ||
|
4bf876296a | ||
|
7088b21f02 | ||
|
3887a4095d | ||
|
a46b6500af | ||
|
304094cbb2 | ||
|
37ccf4dbcf | ||
|
db8a8c0d96 | ||
|
a9caef9eb6 | ||
|
af334986e1 | ||
|
bcd1c22845 | ||
|
75c8f3d2da | ||
|
391e09f76a | ||
|
4725582a0c | ||
|
eb9ea59fe5 | ||
|
d45081bd1a | ||
|
1647e47976 | ||
|
2cbfd83f53 | ||
|
9dd2fa5ce0 | ||
|
e84e9e52e0 | ||
|
6789403599 | ||
|
afa289d9b7 | ||
|
d5b900ce05 | ||
|
1721253616 | ||
|
704471c52d | ||
|
36b73c4398 | ||
|
9ca5b8b2e1 | ||
|
ec7d8ce690 | ||
|
bbf43c88e1 | ||
|
773625a894 | ||
|
feced0f6b2 | ||
|
dbe0ada203 | ||
|
f1137cd36a | ||
|
b408fb3e86 | ||
|
cfb3357a12 | ||
|
167c3507a2 | ||
|
b73d254e76 | ||
|
c8894d3b26 | ||
|
b881675d51 | ||
|
78700f2600 | ||
|
ebfb20c65f | ||
|
ca41ed7db3 | ||
|
d24ee50420 | ||
|
b926f0446a | ||
|
77074962b1 | ||
|
f7518b4d7a | ||
|
dfccc21a18 | ||
|
6829756643 | ||
|
11230d052e | ||
|
6c0dce7b19 | ||
|
2a549f5be5 | ||
|
f78145214a | ||
|
d03f69931c | ||
|
173d80f30e | ||
|
0c00cc0336 | ||
|
b37dfb95e3 | ||
|
dd61f061fc | ||
|
a3094ac5c6 | ||
|
44b82d53e2 | ||
|
bdeaeaa05a | ||
|
e169d99736 | ||
|
2494261ddf | ||
|
2aa9719dd6 | ||
|
57365ba1e4 | ||
|
83ed8122ef | ||
|
2958a8b806 | ||
|
700202ac7b | ||
|
8fe0b5ea02 | ||
|
ed73b3728f | ||
|
8142de8334 | ||
|
dc369a6bad | ||
|
50ca5fc7ff | ||
|
d92a8abe13 | ||
|
6ec6ee0638 | ||
|
ddf231e377 | ||
|
18a034c3fd | ||
|
166ff96c17 | ||
|
c0345c83a6 | ||
|
25b40c94a2 | ||
|
ce5ab6b063 | ||
|
60e119fac0 | ||
|
57acb04a96 | ||
|
bdba64c8c0 | ||
|
e0a302eb40 | ||
|
ddf821f22c | ||
|
f5542683c5 | ||
|
997ce7330e | ||
|
aae04fb75e | ||
|
34a8dfeb97 | ||
|
688a824db2 | ||
|
2521d596d1 | ||
|
dcfcccd5f7 | ||
|
bbe32c5bec | ||
|
be2a7b6b6e | ||
|
d05852c171 | ||
|
6e70402f4a | ||
|
3633545c35 | ||
|
8d6a23f423 | ||
|
173d347c52 | ||
|
a4afe51cb6 | ||
|
976463a87b | ||
|
7ebe21823d | ||
|
e32910172f | ||
|
de82250274 | ||
|
f9be3996f4 | ||
|
ec4060ea2f | ||
|
3d532a29ac | ||
|
a7600dd539 | ||
|
8424b0a6ba | ||
|
ad045075eb | ||
|
4bbfc5465e | ||
|
fa9b227a7b | ||
|
e1adab029d | ||
|
be4dd69f3f | ||
|
b8fac4a7d2 | ||
|
7a1b813cdc | ||
|
78b1f5dc86 | ||
|
a3612c574e | ||
|
9e3d42c5f5 | ||
|
809da21c4a | ||
|
a5a40e80a9 | ||
|
5af0568986 | ||
|
d062b1edce | ||
|
02987bbb98 | ||
|
55a8ec6b39 | ||
|
4ec0962704 | ||
|
eeeb010a43 | ||
|
683a728364 | ||
|
1d07abf659 | ||
|
f8354c1017 | ||
|
e9bc9bd953 | ||
|
495b4402ba | ||
|
5d8f34954f | ||
|
bffb682ef7 | ||
|
44e46c63c3 | ||
|
84baf80b7d | ||
|
565ef3fb3b | ||
|
73afde56d0 | ||
|
6f0303ef56 | ||
|
00c2d6e796 | ||
|
dac6a62ba1 | ||
|
5bf4f824a4 | ||
|
125eaf90cd | ||
|
60afd7ec83 | ||
|
3736e0e711 | ||
|
2f0112497a | ||
|
cabb5d8dbc | ||
|
789af6d8d6 | ||
|
e1e902b3ed | ||
|
88b48315bc | ||
|
efa3b4522f | ||
|
03974c0854 | ||
|
d93bc6b075 | ||
|
2226ad1b90 | ||
|
e8d553b4c0 | ||
|
2dd6f2ebec | ||
|
7d0def16df | ||
|
f262f7d5b5 | ||
|
d2936821b2 | ||
|
e5afda701f | ||
|
0be551b31f | ||
|
986aaa67fb | ||
|
7e6ac47467 | ||
|
5d9101cfc2 | ||
|
fb28d00c02 | ||
|
17ee45ba94 | ||
|
6bafeb5386 | ||
|
a3dd83a529 | ||
|
48b210dcfb | ||
|
a97bdfbe0d | ||
|
3ba6138958 | ||
|
6105ff6641 | ||
|
754e0ed02b | ||
|
91e625b8e4 | ||
|
d5894203c6 | ||
|
e1fcdb8c3d | ||
|
8d1174d569 | ||
|
bbdfa0015e | ||
|
260a3a76f1 | ||
|
c30a43c1fd | ||
|
421c6dd866 | ||
|
7c66b6373a | ||
|
c15dc6c568 | ||
|
3d87e6d743 | ||
|
c92e8a142e | ||
|
011ec950e9 | ||
|
7787fc0ec9 | ||
|
8aea40f72a | ||
|
e6522494a9 | ||
|
c1d4a1bd01 | ||
|
65ff6d1015 | ||
|
072ff1cce3 | ||
|
91eb958dd3 | ||
|
7575020fd5 | ||
|
7410cdf9f6 | ||
|
7c20138161 | ||
|
cee1e59860 | ||
|
1caa7f4344 | ||
|
584847e5b4 | ||
|
ff314754a3 | ||
|
1f499387c6 | ||
|
03f5088d08 | ||
|
cda18f31a5 | ||
|
bfcc4ec4b8 | ||
|
48563f837a | ||
|
7d992029e6 | ||
|
2de8e71d01 | ||
|
bd236b1ac0 | ||
|
e78f1b8045 | ||
|
7eeb6890ff | ||
|
c1c12e9659 | ||
|
4d3686cb05 | ||
|
5e4d4304b5 | ||
|
4e126efdbb | ||
|
6c35842734 | ||
|
7fc5dc33a7 | ||
|
c36649362b | ||
|
cc98e55b9d | ||
|
8fdb514dba | ||
|
4535d08967 | ||
|
30e9089c50 | ||
|
c1f07f5539 | ||
|
fbe97f8858 | ||
|
68ed3dd845 | ||
|
85a32bf8c1 | ||
|
905c5719ef | ||
|
ea39505778 | ||
|
5cd62e6138 | ||
|
844f78b10c | ||
|
28fe0f904f | ||
|
7a26b307ec | ||
|
c491038215 | ||
|
7f87db0768 | ||
|
ea4205db6f | ||
|
69435a0b3e | ||
|
d21e8ee0bb | ||
|
ab6c2cd02f | ||
|
372dc08f26 | ||
|
1745cc16bb | ||
|
dcecae29e9 | ||
|
562e38da7c | ||
|
d468e23f48 |
34 changed files with 4831 additions and 1505 deletions
|
@ -1 +1,6 @@
|
|||
.git
|
||||
*
|
||||
!docker-bench-security.sh
|
||||
!functions/
|
||||
!tests/
|
||||
!log/
|
||||
log/*
|
||||
|
|
19
.github/workflows/issues.yml
vendored
Normal file
19
.github/workflows/issues.yml
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
name: Issue assignment
|
||||
|
||||
on:
|
||||
issues:
|
||||
types: [opened]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
auto-assign:
|
||||
permissions:
|
||||
issues: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 'auto-assign issue'
|
||||
uses: pozil/auto-assign-issue@74b9f64cc1a08f99358061073e243a4c3d7dd5c4 # v1.11.0
|
||||
with:
|
||||
assignees: konstruktoid
|
80
.github/workflows/slsa.yml
vendored
Normal file
80
.github/workflows/slsa.yml
vendored
Normal file
|
@ -0,0 +1,80 @@
|
|||
---
|
||||
name: SLSA
|
||||
on:
|
||||
push:
|
||||
release:
|
||||
permissions:
|
||||
contents: write
|
||||
types: [published, released]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
outputs:
|
||||
hashes: ${{ steps.hash.outputs.hashes }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- run: echo "REPOSITORY_NAME=$(echo '${{ github.repository }}' | awk -F '/' '{print $2}')" >> $GITHUB_ENV
|
||||
shell: bash
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
|
||||
- name: Build artifacts
|
||||
run: |
|
||||
find *.sh functions/* tests/* Dockerfile Vagrantfile -exec sha256sum {} \; > ${{ env.REPOSITORY_NAME }}.sha256
|
||||
|
||||
- name: Generate hashes
|
||||
shell: bash
|
||||
id: hash
|
||||
run: |
|
||||
echo "hashes=$(sha256sum ${{ env.REPOSITORY_NAME }}.sha256 | base64 -w0)" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Upload ${{ env.REPOSITORY_NAME }}.sha256
|
||||
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
|
||||
with:
|
||||
name: ${{ env.REPOSITORY_NAME }}.sha256
|
||||
path: ${{ env.REPOSITORY_NAME }}.sha256
|
||||
if-no-files-found: error
|
||||
retention-days: 5
|
||||
|
||||
provenance:
|
||||
needs: [build]
|
||||
permissions:
|
||||
actions: read
|
||||
id-token: write
|
||||
contents: write
|
||||
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v1.10.0
|
||||
with:
|
||||
base64-subjects: "${{ needs.build.outputs.hashes }}"
|
||||
upload-assets: ${{ startsWith(github.ref, 'refs/tags/') }}
|
||||
|
||||
release:
|
||||
permissions:
|
||||
actions: read
|
||||
id-token: write
|
||||
contents: write
|
||||
needs: [build, provenance]
|
||||
runs-on: ubuntu-latest
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
steps:
|
||||
- run: echo "REPOSITORY_NAME=$(echo '${{ github.repository }}' | awk -F '/' '{print $2}')" >> $GITHUB_ENV
|
||||
shell: bash
|
||||
|
||||
- name: Download ${{ env.REPOSITORY_NAME }}.sha256
|
||||
uses: actions/download-artifact@c850b930e6ba138125429b7e5c93fc707a7f8427 # v4.1.4
|
||||
with:
|
||||
name: ${{ env.REPOSITORY_NAME }}.sha256
|
||||
|
||||
- name: Upload asset
|
||||
uses: softprops/action-gh-release@9d7c94cfd0a1f3ed45544c887983e9fa900f0564 # v2.0.4
|
||||
with:
|
||||
files: |
|
||||
${{ env.REPOSITORY_NAME }}.sha256
|
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -1 +1,3 @@
|
|||
*.log
|
||||
log/*
|
||||
*.swp*
|
||||
.vagrant/
|
||||
|
|
|
@ -3,49 +3,56 @@
|
|||
Want to hack on Docker Bench? Awesome! Here are instructions to get you
|
||||
started.
|
||||
|
||||
The Docker Bench for Security is a part of the [Docker](https://www.docker.com) project, and follows
|
||||
the same rules and principles. If you're already familiar with the way
|
||||
Docker does things, you'll feel right at home.
|
||||
The Docker Bench for Security is a part of the [Docker](https://www.docker.com)
|
||||
project, and follows the same rules and principles. If you're already familiar
|
||||
with the way Docker does things, you'll feel right at home.
|
||||
|
||||
Otherwise, go read
|
||||
[Docker's contributions guidelines](https://github.com/docker/docker/blob/master/CONTRIBUTING.md).
|
||||
[Contribute to the Moby Project](https://github.com/moby/moby/blob/master/CONTRIBUTING.md).
|
||||
|
||||
### Development Environment Setup
|
||||
## Development Environment Setup
|
||||
|
||||
The only thing you need to hack on Docker Bench for Security is a POSIX 2004 compliant shell. We try to keep the project compliant for maximum portability
|
||||
|
||||
#### Start hacking
|
||||
### Start hacking
|
||||
|
||||
You can build the container that wraps the docker-bench for security:
|
||||
|
||||
```sh
|
||||
✗ git clone git@github.com:docker/docker-bench-security.git
|
||||
✗ cd docker-bench-security
|
||||
✗ docker build -t docker-bench-security .
|
||||
git clone git@github.com:docker/docker-bench-security.git
|
||||
cd docker-bench-security
|
||||
docker build -t docker-bench-security .
|
||||
```
|
||||
|
||||
Or you can simply run the shell script locally:
|
||||
|
||||
```sh
|
||||
✗ git clone git@github.com:docker/docker-bench-security.git
|
||||
✗ cd docker-bench-security
|
||||
✗ sh docker-bench-security.sh
|
||||
git clone git@github.com:docker/docker-bench-security.git
|
||||
cd docker-bench-security
|
||||
sudo sh docker-bench-security.sh
|
||||
```
|
||||
|
||||
The Docker Bench has the main script called `docker-bench-security.sh`. This is the main script that checks for all the dependencies, deals with command line arguments and loads all the tests.
|
||||
The Docker Bench has the main script called `docker-bench-security.sh`.
|
||||
This is the main script that checks for all the dependencies, deals with
|
||||
command line arguments and loads all the tests.
|
||||
|
||||
The tests are split in 6 different files:
|
||||
The tests are split into the following files:
|
||||
|
||||
```sh
|
||||
✗ tree tests/
|
||||
tests/
|
||||
├── 1_host_configuration.sh
|
||||
├── 2_docker_daemon_configuration.sh
|
||||
├── 3_docker_daemon_configuration_files.sh
|
||||
├── 4_container_images.sh
|
||||
├── 5_container_runtime.sh
|
||||
└── 6_docker_security_operations.sh
|
||||
├── 6_docker_security_operations.sh
|
||||
├── 7_docker_swarm_configuration.sh
|
||||
├── 8_docker_enterprise_configuration.sh
|
||||
└── 99_community_checks.sh
|
||||
```
|
||||
|
||||
To modify the Docker Bench for Security you should first clone the repository, make your changes, check your code with `shellcheck`, `checkbashisms` or similar tools, and then sign off on your commits. After that feel free to send us a pull-request with the changes.
|
||||
To modify the Docker Bench for Security you should first clone the repository,
|
||||
make your changes, check your code with `shellcheck`, or similar tools, and
|
||||
then sign off on your commits. After that feel free to send us a pull request
|
||||
with the changes.
|
||||
|
||||
While this tool is inspired by the [CIS Docker 1.11.0 benchmark](https://benchmarks.cisecurity.org/downloads/show-single/index.cfm?file=docker16.110), feel free to add new tests. We will try to turn dockerbench.com into a list of good community benchmarks for both security and performance, and we would love community contributions.
|
||||
While this tool was inspired by the [CIS Docker 1.11.0 benchmark](https://www.cisecurity.org/benchmark/docker/)
|
||||
and its successors, feel free to add new tests.
|
||||
|
|
58
CONTRIBUTORS.md
Normal file
58
CONTRIBUTORS.md
Normal file
|
@ -0,0 +1,58 @@
|
|||
The following people, listed in alphabetical order, have contributed to docker-bench-security:
|
||||
|
||||
* alberto <alberto@tutum.co>
|
||||
* Andreas Stieger <astieger@suse.com>
|
||||
* Anthony Roger <aroger@softwaymedical.fr>
|
||||
* Aurélien Gasser <aurelien.gasser@gmail.com>
|
||||
* binary <binary@webdev.fritz.box>
|
||||
* Boris Gorbylev <ekho@ekho.name>
|
||||
* Cheng-Li Jerry Ma <chengli.ma@gmail.com>
|
||||
* Csaba Palfi <csaba@palfi.me>
|
||||
* Daniele Marcocci <daniele.marcocci@par-tec.it>
|
||||
* Dhawal Patel <dhawal.patel@nordstrom.com>
|
||||
* Diogo Monica <diogo@docker.com>
|
||||
* Diogo Mónica <diogo.monica@gmail.com>
|
||||
* Ernst de Haan <ernst@ernstdehaan.com>
|
||||
* HuKeping <hukeping@huawei.com>
|
||||
* Ivan Angelov <iangelov@users.noreply.github.com>
|
||||
* J0WI <J0WI@users.noreply.github.com>
|
||||
* jammasterj89 <jammasterj89@gmail.com>
|
||||
* Jessica Frazelle <princess@docker.com>
|
||||
* Joachim Lusiardi <jlusiardi@users.noreply.github.com>
|
||||
* Joachim Lusiardi <joachim@lusiardi.de>
|
||||
* Joachim Lusiardi <shing19m@dev1.lusiardi.de>
|
||||
* Joe Williams <joe.williams@github.com>
|
||||
* Julien Garcia Gonzalez <julien@giantswarm.io>
|
||||
* Jürgen Hermann <jh@web.de>
|
||||
* kakakakakku <y.yoshida22@gmail.com>
|
||||
* Karol Babioch <kbabioch@suse.de>
|
||||
* Kevin Lim <kevin.lim@sap.com>
|
||||
* kevinll <imhael@gmail.com>
|
||||
* Liron Levin <liron@twistlock.com>
|
||||
* liron-l <levinlir@gmail.com>
|
||||
* LorensK <LorensK@users.noreply.github.com>
|
||||
* lusitania <lusitania@users.noreply.github.com>
|
||||
* Maik Ellerbrock <opensource@frapsoft.com>
|
||||
* Mark Stemm <mark.stemm@gmail.com>
|
||||
* Matt Fellows <matt.fellows@onegeek.com.au>
|
||||
* Michael Crosby <crosbymichael@gmail.com>
|
||||
* Michael Stahn <michael.stahn.42@gmail.com>
|
||||
* Mike Ritter <mike.ritter@target.com>
|
||||
* Mr. Secure <ben.github@mrsecure.org>
|
||||
* MrSecure <MrSecure@users.noreply.github.com>
|
||||
* Nigel Brown <nigel@windsock.io>
|
||||
* Paul Czarkowski <username.taken@gmail.com>
|
||||
* Paul Morgan <jumanjiman@gmail.com>
|
||||
* Pete Sellars <psellars@gmail.com>
|
||||
* Peter <lusitania@users.noreply.github.com>
|
||||
* Ravi Kumar Vadapalli <vadapalli.ravikumar@gmail.com>
|
||||
* Scott McCarty <scott.mccarty@gmail.com>
|
||||
* Sebastiaan van Stijn <github@gone.nl>
|
||||
* telepresencebot2 <telepresencebot2@users.noreply.github.com>
|
||||
* Thomas Sjögren <konstruktoid@users.noreply.github.com>
|
||||
* Tom Partington <tom.partington@cevo.com.au>
|
||||
* Werner Buck <wernerbuck@gmail.com>
|
||||
* will Farrell <willfarrell@users.noreply.github.com>
|
||||
* Zvi "Viz" Effron <zeffron@riotgames.com>
|
||||
|
||||
This list was generated Tue Nov 5 09:45:35 UTC 2019.
|
40
Dockerfile
40
Dockerfile
|
@ -1,32 +1,20 @@
|
|||
FROM alpine:3.5
|
||||
FROM alpine:3.18@sha256:eece025e432126ce23f223450a0326fbebde39cdf496a85d8c016293fc851978
|
||||
|
||||
LABEL org.label-schema.name="docker-bench-security" \
|
||||
org.label-schema.url="https://dockerbench.com" \
|
||||
org.label-schema.vcs-url="https://github.com/docker/docker-bench-security.git"
|
||||
LABEL \
|
||||
org.label-schema.name="docker-bench-security" \
|
||||
org.label-schema.url="https://dockerbench.com" \
|
||||
org.label-schema.vcs-url="https://github.com/docker/docker-bench-security.git"
|
||||
|
||||
ENV VERSION 1.12.6
|
||||
ENV SHA256 cadc6025c841e034506703a06cf54204e51d0cadfae4bae62628ac648d82efdd
|
||||
RUN apk add --no-cache iproute2 \
|
||||
docker-cli \
|
||||
dumb-init \
|
||||
jq
|
||||
|
||||
WORKDIR /usr/bin
|
||||
COPY . /usr/local/bin/
|
||||
|
||||
RUN apk update && \
|
||||
apk upgrade && \
|
||||
apk --update add coreutils wget ca-certificates && \
|
||||
wget https://get.docker.com/builds/Linux/x86_64/docker-$VERSION.tgz && \
|
||||
wget https://get.docker.com/builds/Linux/x86_64/docker-$VERSION.tgz.sha256 && \
|
||||
sha256sum -c docker-$VERSION.tgz.sha256 && \
|
||||
echo "$SHA256 docker-$VERSION.tgz" | sha256sum -c - && \
|
||||
tar -xzvf docker-$VERSION.tgz -C /tmp && \
|
||||
mv /tmp/docker/docker . && \
|
||||
chmod u+x docker* && \
|
||||
rm -rf /tmp/docker* && \
|
||||
apk del wget ca-certificates && \
|
||||
rm -rf /var/cache/apk/* docker-$VERSION.tgz docker-$VERSION.tgz.sha256
|
||||
HEALTHCHECK CMD exit 0
|
||||
|
||||
RUN mkdir /docker-bench-security
|
||||
WORKDIR /usr/local/bin
|
||||
|
||||
COPY . /docker-bench-security
|
||||
|
||||
WORKDIR /docker-bench-security
|
||||
|
||||
ENTRYPOINT ["/bin/sh", "docker-bench-security.sh"]
|
||||
ENTRYPOINT [ "/usr/bin/dumb-init", "/bin/sh", "docker-bench-security.sh" ]
|
||||
CMD [""]
|
||||
|
|
|
@ -30,5 +30,5 @@
|
|||
|
||||
[people.konstruktoid]
|
||||
Name = "Thomas Sjögren"
|
||||
Email = "thomas.sjogren@outlook.com"
|
||||
Email = "thomas.sjogren@protonmail.com"
|
||||
GitHub = "konstruktoid"
|
||||
|
|
184
README.md
184
README.md
|
@ -1,68 +1,51 @@
|
|||
# Docker Bench for Security
|
||||
|
||||

|
||||

|
||||
|
||||
The Docker Bench for Security is a script that checks for dozens of common
|
||||
best-practices around deploying Docker containers in production. The tests are
|
||||
all automated, and are inspired by the [CIS Docker 1.12 Benchmark](https://benchmarks.cisecurity.org/tools2/docker/CIS_Docker_1.12.0_Benchmark_v1.0.0.pdf).
|
||||
We are releasing this as a follow-up to our [Understanding Docker Security and Best Practices](https://blog.docker.com/2015/05/understanding-docker-security-and-best-practices/)
|
||||
blog post.
|
||||
The Docker Bench for Security is a script that checks for dozens of common best-practices around deploying Docker containers in production. The tests are all automated, and are based on the [CIS Docker Benchmark v1.6.0](https://www.cisecurity.org/benchmark/docker/).
|
||||
|
||||
We are making this available as an open-source utility so the Docker community
|
||||
can have an easy way to self-assess their hosts and docker containers against
|
||||
this benchmark.
|
||||
We are making this available as an open-source utility so the Docker community can have an easy way to self-assess their hosts and Docker containers against this benchmark.
|
||||
|
||||
Release | CIS |
|
||||
:---:|:---:|
|
||||
1.6.0|1.6.0|
|
||||
1.5.0|1.5.0|
|
||||
1.3.6|1.4.0|
|
||||
1.3.5|1.2.0|
|
||||
1.3.3|1.1.0|
|
||||
1.3.0|1.13.0|
|
||||
|
||||
## Running Docker Bench for Security
|
||||
|
||||
We packaged docker bench as a small container for your convenience. Note that
|
||||
this container is being run with a *lot* of privilege -- sharing the host's
|
||||
filesystem, pid and network namespaces, due to portions of the benchmark
|
||||
applying to the running host. Don't forget to adjust the shared volumes
|
||||
according to your operating system, it may not for example use systemd.
|
||||
### Run from your base host
|
||||
|
||||
The easiest way to run your hosts against the Docker Bench for Security is by
|
||||
running our pre-built container:
|
||||
|
||||
```sh
|
||||
docker run -it --net host --pid host --cap-add audit_control \
|
||||
-e DOCKER_CONTENT_TRUST=$DOCKER_CONTENT_TRUST \
|
||||
-v /var/lib:/var/lib \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
-v /usr/lib/systemd:/usr/lib/systemd \
|
||||
-v /etc:/etc --label docker_bench_security \
|
||||
docker/docker-bench-security
|
||||
```
|
||||
|
||||
Docker bench requires Docker 1.10.0 or later in order to run.
|
||||
|
||||
Also note that the default image and `Dockerfile` uses `FROM: alpine` which
|
||||
doesn't contain `auditctl`, this will generate errors in section 1.8 to 1.15.
|
||||
Distribution specific Dockerfiles that fixes this issue are available in the
|
||||
[distros directory](https://github.com/docker/docker-bench-security/tree/master/distros).
|
||||
|
||||
The [distribution specific Dockerfiles](https://github.com/docker/docker-bench-security/tree/master/distros)
|
||||
may also help if the distribution you're using haven't yet shipped Docker
|
||||
version 1.10.0 or later.
|
||||
|
||||
## Building Docker Bench for Security
|
||||
|
||||
If you wish to build and run this container yourself, you can follow the
|
||||
following steps:
|
||||
You can simply run this script from your base host by running:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/docker/docker-bench-security.git
|
||||
cd docker-bench-security
|
||||
docker build -t docker-bench-security .
|
||||
docker run -it --net host --pid host --cap-add audit_control \
|
||||
-e DOCKER_CONTENT_TRUST=$DOCKER_CONTENT_TRUST \
|
||||
-v /var/lib:/var/lib \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
-v /usr/lib/systemd:/usr/lib/systemd \
|
||||
-v /etc:/etc --label docker_bench_security \
|
||||
docker-bench-security
|
||||
sudo sh docker-bench-security.sh
|
||||
```
|
||||
|
||||
or use [Docker Compose](https://docs.docker.com/compose/):
|
||||
> Note: [`jq`](https://jqlang.github.io/jq/) is an optional but recommended dependency.
|
||||
|
||||
### Run with Docker
|
||||
|
||||
#### Building Docker image
|
||||
|
||||
You have two options if you wish to build and run this container yourself:
|
||||
|
||||
1. Use Docker Build:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/docker/docker-bench-security.git
|
||||
cd docker-bench-security
|
||||
docker build --no-cache -t docker-bench-security .
|
||||
```
|
||||
|
||||
Followed by an appropriate `docker run` command as stated below.
|
||||
|
||||
2. Use Docker Compose:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/docker/docker-bench-security.git
|
||||
|
@ -70,13 +53,100 @@ cd docker-bench-security
|
|||
docker-compose run --rm docker-bench-security
|
||||
```
|
||||
|
||||
Also, this script can also be simply run from your base host by running:
|
||||
_Please note that the `docker/docker-bench-security` image is out-of-date and and a manual build is required. See [#405](https://github.com/docker/docker-bench-security/issues/405) for more information._
|
||||
|
||||
Note that this container is being run with a *lot* of privilege -- sharing the host's filesystem, pid and network namespaces, due to portions of the benchmark applying to the running host.
|
||||
|
||||
### Using the container
|
||||
|
||||
```sh
|
||||
git clone https://github.com/docker/docker-bench-security.git
|
||||
cd docker-bench-security
|
||||
sh docker-bench-security.sh
|
||||
docker run --rm --net host --pid host --userns host --cap-add audit_control \
|
||||
-e DOCKER_CONTENT_TRUST=$DOCKER_CONTENT_TRUST \
|
||||
-v /etc:/etc:ro \
|
||||
-v /usr/bin/containerd:/usr/bin/containerd:ro \
|
||||
-v /usr/bin/runc:/usr/bin/runc:ro \
|
||||
-v /usr/lib/systemd:/usr/lib/systemd:ro \
|
||||
-v /var/lib:/var/lib:ro \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock:ro \
|
||||
--label docker_bench_security \
|
||||
docker-bench-security
|
||||
```
|
||||
|
||||
This script was build to be POSIX 2004 compliant, so it should be portable
|
||||
across any Unix platform.
|
||||
Don't forget to adjust the shared volumes according to your operating system.
|
||||
Some examples are:
|
||||
|
||||
1. On Ubuntu the `docker.service` and `docker.secret` files are located in
|
||||
`/lib/systemd/system` folder by default.
|
||||
|
||||
```sh
|
||||
docker run --rm --net host --pid host --userns host --cap-add audit_control \
|
||||
-e DOCKER_CONTENT_TRUST=$DOCKER_CONTENT_TRUST \
|
||||
-v /etc:/etc:ro \
|
||||
-v /lib/systemd/system:/lib/systemd/system:ro \
|
||||
-v /usr/bin/containerd:/usr/bin/containerd:ro \
|
||||
-v /usr/bin/runc:/usr/bin/runc:ro \
|
||||
-v /usr/lib/systemd:/usr/lib/systemd:ro \
|
||||
-v /var/lib:/var/lib:ro \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock:ro \
|
||||
--label docker_bench_security \
|
||||
docker-bench-security
|
||||
```
|
||||
|
||||
2. The /etc/hostname file is missing on macOS, so it will need to be created first. Also, `Docker Desktop` on macOS doesn't have `/usr/lib/systemd` or the above Docker
|
||||
binaries.
|
||||
|
||||
```sh
|
||||
sudo touch /etc/hostname
|
||||
|
||||
docker run --rm --net host --pid host --userns host --cap-add audit_control \
|
||||
-e DOCKER_CONTENT_TRUST=$DOCKER_CONTENT_TRUST \
|
||||
-v /etc:/etc \
|
||||
-v /var/lib:/var/lib:ro \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock:ro \
|
||||
--label docker_bench_security \
|
||||
docker-bench-security
|
||||
```
|
||||
|
||||
### Note
|
||||
|
||||
Docker bench requires Docker 1.13.0 or later in order to run.
|
||||
|
||||
Note that when distributions don't contain `auditctl`, the audit tests will check `/etc/audit/audit.rules` to see if a rule is present instead.
|
||||
|
||||
### Docker Bench for Security options
|
||||
|
||||
```sh
|
||||
-b optional Do not print colors
|
||||
-h optional Print this help message
|
||||
-l FILE optional Log output in FILE, inside container if run using docker
|
||||
-u USERS optional Comma delimited list of trusted docker user(s)
|
||||
-c CHECK optional Comma delimited list of specific check(s) id
|
||||
-e CHECK optional Comma delimited list of specific check(s) id to exclude
|
||||
-i INCLUDE optional Comma delimited list of patterns within a container or image name to check
|
||||
-x EXCLUDE optional Comma delimited list of patterns within a container or image name to exclude from check
|
||||
-t LABEL optional Comma delimited list of labels within a container or image to check
|
||||
-n LIMIT optional In JSON output, when reporting lists of items (containers, images, etc.), limit the number of reported items to LIMIT. Default 0 (no limit).
|
||||
-p PRINT optional Disable the printing of remediation measures. Default: print remediation measures.
|
||||
```
|
||||
|
||||
By default the Docker Bench for Security script will run all available CIS tests and produce
|
||||
logs in the log folder from current directory, named `docker-bench-security.log.json` and
|
||||
`docker-bench-security.log`.
|
||||
|
||||
If the docker container is used then the log files will be created inside the container in location `/usr/local/bin/log/`. If you wish to access them from the host after the container has been run you will need to mount a volume for storing them in.
|
||||
|
||||
The CIS based checks are named `check_<section>_<number>`, e.g. `check_2_6` and community contributed checks are named `check_c_<number>`.
|
||||
|
||||
`sh docker-bench-security.sh -c check_2_2` will only run check `2.2 Ensure the logging level is set to 'info'`.
|
||||
|
||||
`sh docker-bench-security.sh -e check_2_2` will run all available checks except `2.2 Ensure the logging level is set to 'info'`.
|
||||
|
||||
`sh docker-bench-security.sh -e docker_enterprise_configuration` will run all available checks except the docker_enterprise_configuration group
|
||||
|
||||
`sh docker-bench-security.sh -e docker_enterprise_configuration,check_2_2` will run all available checks except the docker_enterprise_configuration group and `2.2 Ensure the logging level is set to 'info'`
|
||||
|
||||
`sh docker-bench-security.sh -c container_images,container_runtime` will run just the container_images and container_runtime checks
|
||||
|
||||
`sh docker-bench-security.sh -c container_images -e check_4_5` will run just the container_images checks except `4.5 Ensure Content trust for Docker is Enabled`
|
||||
|
||||
Note that when submitting checks, provide information why it is a reasonable test to add and please include some kind of official documentation verifying that information.
|
||||
|
|
19
Vagrantfile
vendored
Normal file
19
Vagrantfile
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
Vagrant.configure("2") do |config|
|
||||
config.vbguest.installer_options = { allow_kernel_upgrade: true }
|
||||
config.vm.provider "virtualbox" do |v|
|
||||
v.memory = 2048
|
||||
v.cpus = 2
|
||||
v.customize ["modifyvm", :id, "--uart1", "0x3F8", "4"]
|
||||
v.customize ["modifyvm", :id, "--uartmode1", "file", File::NULL]
|
||||
end
|
||||
|
||||
config.vm.define "jammy" do |jammy|
|
||||
jammy.ssh.extra_args = ["-o","ConnectTimeout=600"]
|
||||
jammy.ssh.insert_key = true
|
||||
jammy.vm.boot_timeout = 600
|
||||
jammy.vm.box = "ubuntu/jammy64"
|
||||
jammy.vm.hostname = "jammy"
|
||||
jammy.vm.provision "shell",
|
||||
inline: "apt-get update && curl -sSL get.docker.com | sh && addgroup vagrant docker"
|
||||
end
|
||||
end
|
Binary file not shown.
Before ![]() (image error) Size: 66 KiB |
|
@ -1,32 +0,0 @@
|
|||
FROM alpine:3.5
|
||||
|
||||
LABEL org.label-schema.name="docker-bench-security" \
|
||||
org.label-schema.url="https://dockerbench.com" \
|
||||
org.label-schema.vcs-url="https://github.com/docker/docker-bench-security.git"
|
||||
|
||||
ENV VERSION 1.12.6
|
||||
ENV SHA256 cadc6025c841e034506703a06cf54204e51d0cadfae4bae62628ac648d82efdd
|
||||
|
||||
WORKDIR /usr/bin
|
||||
|
||||
RUN apk update && \
|
||||
apk upgrade && \
|
||||
apk --update add coreutils wget ca-certificates && \
|
||||
wget https://get.docker.com/builds/Linux/x86_64/docker-$VERSION.tgz && \
|
||||
wget https://get.docker.com/builds/Linux/x86_64/docker-$VERSION.tgz.sha256 && \
|
||||
sha256sum -c docker-$VERSION.tgz.sha256 && \
|
||||
echo "$SHA256 docker-$VERSION.tgz" | sha256sum -c - && \
|
||||
tar -xzvf docker-$VERSION.tgz -C /tmp && \
|
||||
mv /tmp/docker/docker . && \
|
||||
chmod u+x docker* && \
|
||||
rm -rf /tmp/docker* && \
|
||||
apk del wget ca-certificates && \
|
||||
rm -rf /var/cache/apk/* docker-$VERSION.tgz docker-$VERSION.tgz.sha256
|
||||
|
||||
RUN mkdir /docker-bench-security
|
||||
|
||||
COPY . /docker-bench-security
|
||||
|
||||
WORKDIR /docker-bench-security
|
||||
|
||||
ENTRYPOINT ["/bin/sh", "docker-bench-security.sh"]
|
|
@ -1,15 +0,0 @@
|
|||
# REPOSITORY https://github.com/fatherlinux/docker-bench-security
|
||||
|
||||
FROM centos
|
||||
|
||||
MAINTAINER smccarty@redhat.com
|
||||
|
||||
RUN yum install -y docker net-tools audit procps-ng; yum clean all
|
||||
|
||||
RUN mkdir /docker-bench-security
|
||||
|
||||
COPY . /docker-bench-security
|
||||
|
||||
WORKDIR /docker-bench-security
|
||||
|
||||
ENTRYPOINT ["/bin/sh", "docker-bench-security.sh"]
|
|
@ -1,24 +0,0 @@
|
|||
FROM debian:sid
|
||||
|
||||
LABEL org.label-schema.name="docker-bench-security" \
|
||||
org.label-schema.url="https://github.com/konstruktoid/docker-bench-security" \
|
||||
org.label-schema.vcs-url="https://github.com/konstruktoid/docker-bench-security.git"
|
||||
|
||||
RUN \
|
||||
apt-get update && \
|
||||
apt-get -y upgrade && \
|
||||
apt-get -y install auditd ca-certificates docker.io \
|
||||
gawk net-tools procps --no-install-recommends && \
|
||||
apt-get -y clean && \
|
||||
apt-get -y autoremove && \
|
||||
rm -rf /var/lib/apt/lists/* \
|
||||
/usr/share/doc /usr/share/doc-base \
|
||||
/usr/share/man /usr/share/locale /usr/share/zoneinfo
|
||||
|
||||
RUN mkdir /docker-bench-security
|
||||
|
||||
COPY . /docker-bench-security
|
||||
|
||||
WORKDIR /docker-bench-security
|
||||
|
||||
ENTRYPOINT ["/bin/sh", "docker-bench-security.sh"]
|
|
@ -1,15 +0,0 @@
|
|||
# REPOSITORY https://github.com/docker/docker-bench-security
|
||||
|
||||
FROM opensuse
|
||||
|
||||
MAINTAINER security@suse.com
|
||||
|
||||
RUN zypper -n in docker net-tools audit
|
||||
|
||||
RUN mkdir /docker-bench-security
|
||||
|
||||
COPY . /docker-bench-security
|
||||
|
||||
WORKDIR /docker-bench-security
|
||||
|
||||
ENTRYPOINT ["/bin/sh", "docker-bench-security.sh"]
|
|
@ -1,18 +0,0 @@
|
|||
# REPOSITORY https://github.com/fatherlinux/docker-bench-security
|
||||
|
||||
FROM rhel7
|
||||
|
||||
MAINTAINER smccarty@redhat.com
|
||||
|
||||
RUN yum install -y yum-utils; yum clean all
|
||||
RUN yum-config-manager --disable "*" &>/dev/null
|
||||
RUN yum-config-manager --enable rhel-7-server-rpms --enable rhel-7-server-extras-rpms
|
||||
RUN yum install -y docker net-tools audit procps-ng; yum clean all
|
||||
|
||||
RUN mkdir /docker-bench-security
|
||||
|
||||
COPY . /docker-bench-security
|
||||
|
||||
WORKDIR /docker-bench-security
|
||||
|
||||
ENTRYPOINT ["/bin/sh", "docker-bench-security.sh"]
|
|
@ -1,18 +0,0 @@
|
|||
# Distribution specific Dockerfiles
|
||||
|
||||
## Requirements
|
||||
|
||||
### Dockerfile name
|
||||
The format should be `Dockerfile.{distribution name}`.
|
||||
|
||||
### Keep your images up-to-date
|
||||
Use the distribution package manager to keep your image up-to-date.
|
||||
|
||||
### REPOSITORY
|
||||
Add a `REPOSITORY` comment with the URL to your GitHub repository where the Dockerfile is present.
|
||||
`# REPOSITORY <GitHub repository>`
|
||||
|
||||
### MAINTAINER
|
||||
Add the `MAINTAINER` instruction and your contact details, GitHub aliases are acceptable.
|
||||
|
||||
For an example Dockerfile, please refer to `Dockerfile.alpine`.
|
|
@ -1,96 +1,222 @@
|
|||
#!/bin/sh
|
||||
# ------------------------------------------------------------------------------
|
||||
# Docker Bench for Security v1.2.0
|
||||
#!/bin/bash
|
||||
# --------------------------------------------------------------------------------------------
|
||||
# Docker Bench for Security
|
||||
#
|
||||
# Docker, Inc. (c) 2015-
|
||||
# Docker, Inc. (c) 2015-2022
|
||||
#
|
||||
# Checks for dozens of common best-practices around deploying Docker containers in production.
|
||||
# Inspired by the CIS Docker 1.12 Benchmark.
|
||||
# ------------------------------------------------------------------------------
|
||||
# --------------------------------------------------------------------------------------------
|
||||
|
||||
version='1.6.0'
|
||||
|
||||
LIBEXEC="." # Distributions can change this to /usr/libexec or similar.
|
||||
|
||||
# Load dependencies
|
||||
. ./output_lib.sh
|
||||
. ./helper_lib.sh
|
||||
. $LIBEXEC/functions/functions_lib.sh
|
||||
. $LIBEXEC/functions/helper_lib.sh
|
||||
|
||||
# Setup the paths
|
||||
this_path=$(abspath "$0") ## Path of this file including filenamel
|
||||
myname=$(basename "${this_path}") ## file name of this script.
|
||||
this_path=$(abspath "$0") ## Path of this file including filename
|
||||
myname=$(basename "${this_path%.*}") ## file name of this script.
|
||||
|
||||
export PATH=/bin:/sbin:/usr/bin:/usr/local/bin:/usr/sbin/
|
||||
readonly version
|
||||
readonly this_path
|
||||
readonly myname
|
||||
|
||||
export PATH="$PATH:/bin:/sbin:/usr/bin:/usr/local/bin:/usr/sbin/"
|
||||
|
||||
# Check for required program(s)
|
||||
req_progs='awk docker grep netstat stat'
|
||||
for p in $req_progs; do
|
||||
command -v "$p" >/dev/null 2>&1 || { printf "%s command not found.\n" "$p"; exit 1; }
|
||||
done
|
||||
req_programs 'awk docker grep sed stat tail tee tr wc xargs'
|
||||
|
||||
# Ensure we can connect to docker daemon
|
||||
docker ps -q >/dev/null 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
if ! docker ps -q >/dev/null 2>&1; then
|
||||
printf "Error connecting to docker daemon (does docker ps work?)\n"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
usage () {
|
||||
cat <<EOF
|
||||
usage: ${myname} [options]
|
||||
Docker Bench for Security - Docker, Inc. (c) 2015-$(date +"%Y")
|
||||
Checks for dozens of common best-practices around deploying Docker containers in production.
|
||||
Based on the CIS Docker Benchmark 1.6.0.
|
||||
|
||||
Usage: ${myname}.sh [OPTIONS]
|
||||
|
||||
Example:
|
||||
- Only run check "2.2 - Ensure the logging level is set to 'info'":
|
||||
sh docker-bench-security.sh -c check_2_2
|
||||
- Run all available checks except the host_configuration group and "2.8 - Enable user namespace support":
|
||||
sh docker-bench-security.sh -e host_configuration,check_2_8
|
||||
- Run just the container_images checks except "4.5 - Ensure Content trust for Docker is Enabled":
|
||||
sh docker-bench-security.sh -c container_images -e check_4_5
|
||||
|
||||
Options:
|
||||
-b optional Do not print colors
|
||||
-h optional Print this help message
|
||||
-l PATH optional Log output in PATH
|
||||
-l FILE optional Log output in FILE, inside container if run using docker
|
||||
-u USERS optional Comma delimited list of trusted docker user(s)
|
||||
-c CHECK optional Comma delimited list of specific check(s) id
|
||||
-e CHECK optional Comma delimited list of specific check(s) id to exclude
|
||||
-i INCLUDE optional Comma delimited list of patterns within a container or image name to check
|
||||
-x EXCLUDE optional Comma delimited list of patterns within a container or image name to exclude from check
|
||||
-t LABEL optional Comma delimited list of labels within a container or image to check
|
||||
-n LIMIT optional In JSON output, when reporting lists of items (containers, images, etc.), limit the number of reported items to LIMIT. Default 0 (no limit).
|
||||
-p PRINT optional Print remediation measures. Default: Don't print remediation measures.
|
||||
|
||||
Complete list of checks: <https://github.com/docker/docker-bench-security/blob/master/tests/>
|
||||
Full documentation: <https://github.com/docker/docker-bench-security>
|
||||
Released under the Apache-2.0 License.
|
||||
EOF
|
||||
}
|
||||
|
||||
# Default values
|
||||
if [ ! -d log ]; then
|
||||
mkdir log
|
||||
fi
|
||||
|
||||
logger="log/${myname}.log"
|
||||
limit=0
|
||||
printremediation="0"
|
||||
globalRemediation=""
|
||||
|
||||
# Get the flags
|
||||
# If you add an option here, please
|
||||
# remember to update usage() above.
|
||||
while getopts hl: args
|
||||
while getopts bhl:u:c:e:i:x:t:n:p args
|
||||
do
|
||||
case $args in
|
||||
b) nocolor="nocolor";;
|
||||
h) usage; exit 0 ;;
|
||||
l) logger="$OPTARG" ;;
|
||||
u) dockertrustusers="$OPTARG" ;;
|
||||
c) check="$OPTARG" ;;
|
||||
e) checkexclude="$OPTARG" ;;
|
||||
i) include="$OPTARG" ;;
|
||||
x) exclude="$OPTARG" ;;
|
||||
t) labels="$OPTARG" ;;
|
||||
n) limit="$OPTARG" ;;
|
||||
p) printremediation="1" ;;
|
||||
*) usage; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ -z "$logger" ]; then
|
||||
logger="${myname}.log"
|
||||
fi
|
||||
# Load output formating
|
||||
. $LIBEXEC/functions/output_lib.sh
|
||||
|
||||
yell "# ------------------------------------------------------------------------------
|
||||
# Docker Bench for Security v1.2.0
|
||||
#
|
||||
# Docker, Inc. (c) 2015-
|
||||
#
|
||||
# Checks for dozens of common best-practices around deploying Docker containers in production.
|
||||
# Inspired by the CIS Docker 1.12 Benchmark.
|
||||
# ------------------------------------------------------------------------------"
|
||||
yell_info
|
||||
|
||||
# Warn if not root
|
||||
ID=$(id -u)
|
||||
if [ "x$ID" != "x0" ]; then
|
||||
warn "Some tests might require root to run"
|
||||
sleep 3
|
||||
if [ "$(id -u)" != "0" ]; then
|
||||
warn "$(yell 'Some tests might require root to run')\n"
|
||||
sleep 3
|
||||
fi
|
||||
|
||||
logit "Initializing $(date)\n"
|
||||
# Total Score
|
||||
# Warn Scored -1, Pass Scored +1, Not Score -0
|
||||
|
||||
totalChecks=0
|
||||
currentScore=0
|
||||
|
||||
logit "Initializing $(date +%Y-%m-%dT%H:%M:%S%:z)\n"
|
||||
beginjson "$version" "$(date +%s)"
|
||||
|
||||
# Load all the tests from tests/ and run them
|
||||
main () {
|
||||
# List all running containers
|
||||
containers=$(docker ps | sed '1d' | awk '{print $NF}')
|
||||
logit "\n${bldylw}Section A - Check results${txtrst}"
|
||||
|
||||
# Get configuration location
|
||||
get_docker_configuration_file
|
||||
|
||||
# If there is a container with label docker_bench_security, memorize it:
|
||||
benchcont="nil"
|
||||
for c in $containers; do
|
||||
labels=$(docker inspect --format '{{ .Config.Labels }}' "$c")
|
||||
contains "$labels" "docker_bench_security" && benchcont="$c"
|
||||
for c in $(docker ps | sed '1d' | awk '{print $NF}'); do
|
||||
if docker inspect --format '{{ .Config.Labels }}' "$c" | \
|
||||
grep -e 'docker.bench.security' >/dev/null 2>&1; then
|
||||
benchcont="$c"
|
||||
fi
|
||||
done
|
||||
# List all running containers except docker-bench (use names to improve readability in logs)
|
||||
containers=$(docker ps | sed '1d' | awk '{print $NF}' | grep -v "$benchcont")
|
||||
|
||||
for test in tests/*.sh
|
||||
do
|
||||
. ./"$test"
|
||||
# Get the image id of the docker_bench_security_image, memorize it:
|
||||
benchimagecont="nil"
|
||||
for c in $(docker images | sed '1d' | awk '{print $3}'); do
|
||||
if docker inspect --format '{{ .Config.Labels }}' "$c" | \
|
||||
grep -e 'docker.bench.security' >/dev/null 2>&1; then
|
||||
benchimagecont="$c"
|
||||
fi
|
||||
done
|
||||
|
||||
# Format LABELS
|
||||
for label in $(echo "$labels" | sed 's/,/ /g'); do
|
||||
LABELS="$LABELS --filter label=$label"
|
||||
done
|
||||
|
||||
if [ -n "$include" ]; then
|
||||
pattern=$(echo "$include" | sed 's/,/|/g')
|
||||
containers=$(docker ps $LABELS| sed '1d' | awk '{print $NF}' | grep -v "$benchcont" | grep -E "$pattern")
|
||||
images=$(docker images $LABELS| sed '1d' | grep -E "$pattern" | awk '{print $3}' | grep -v "$benchimagecont")
|
||||
elif [ -n "$exclude" ]; then
|
||||
pattern=$(echo "$exclude" | sed 's/,/|/g')
|
||||
containers=$(docker ps $LABELS| sed '1d' | awk '{print $NF}' | grep -v "$benchcont" | grep -Ev "$pattern")
|
||||
images=$(docker images $LABELS| sed '1d' | grep -Ev "$pattern" | awk '{print $3}' | grep -v "$benchimagecont")
|
||||
else
|
||||
containers=$(docker ps $LABELS| sed '1d' | awk '{print $NF}' | grep -v "$benchcont")
|
||||
images=$(docker images -q $LABELS| grep -v "$benchcont")
|
||||
fi
|
||||
|
||||
for test in $LIBEXEC/tests/*.sh; do
|
||||
. "$test"
|
||||
done
|
||||
|
||||
if [ -z "$check" ] && [ ! "$checkexclude" ]; then
|
||||
# No options just run
|
||||
cis
|
||||
elif [ -z "$check" ]; then
|
||||
# No check defined but excludes defined set to calls in cis() function
|
||||
check=$(sed -ne "/cis() {/,/}/{/{/d; /}/d; p;}" functions/functions_lib.sh)
|
||||
fi
|
||||
|
||||
for c in $(echo "$check" | sed "s/,/ /g"); do
|
||||
if ! command -v "$c" 2>/dev/null 1>&2; then
|
||||
echo "Check \"$c\" doesn't seem to exist."
|
||||
continue
|
||||
fi
|
||||
if [ -z "$checkexclude" ]; then
|
||||
# No excludes just run the checks specified
|
||||
"$c"
|
||||
else
|
||||
# Exludes specified and check exists
|
||||
checkexcluded="$(echo ",$checkexclude" | sed -e 's/^/\^/g' -e 's/,/\$|/g' -e 's/$/\$/g')"
|
||||
|
||||
if echo "$c" | grep -E "$checkexcluded" 2>/dev/null 1>&2; then
|
||||
# Excluded
|
||||
continue
|
||||
elif echo "$c" | grep -vE 'check_[0-9]|check_[a-z]' 2>/dev/null 1>&2; then
|
||||
# Function not a check, fill loop_checks with all check from function
|
||||
loop_checks="$(sed -ne "/$c() {/,/}/{/{/d; /}/d; p;}" functions/functions_lib.sh)"
|
||||
else
|
||||
# Just one check
|
||||
loop_checks="$c"
|
||||
fi
|
||||
|
||||
for lc in $loop_checks; do
|
||||
if echo "$lc" | grep -vE "$checkexcluded" 2>/dev/null 1>&2; then
|
||||
# Not excluded
|
||||
"$lc"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -n "${globalRemediation}" ] && [ "$printremediation" = "1" ]; then
|
||||
logit "\n\n${bldylw}Section B - Remediation measures${txtrst}"
|
||||
logit "${globalRemediation}"
|
||||
fi
|
||||
|
||||
logit "\n\n${bldylw}Section C - Score${txtrst}\n"
|
||||
info "Checks: $totalChecks"
|
||||
info "Score: $currentScore\n"
|
||||
|
||||
endjson "$totalChecks" "$currentScore" "$(date +%s)"
|
||||
}
|
||||
|
||||
main "$@"
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
docker-bench-security:
|
||||
# use image if you have a dedicated build step:
|
||||
# docker build --rm -t docker-bench-security .
|
||||
# image: docker-bench-security
|
||||
services:
|
||||
docker-bench-security:
|
||||
# use image if you have a dedicated build step:
|
||||
# docker build --rm -t docker-bench-security .
|
||||
# image: docker-bench-security
|
||||
|
||||
# use build path to Dockerfile if docker-compose should build the image
|
||||
build: .
|
||||
# use build path to Dockerfile if docker-compose should build the image
|
||||
build: .
|
||||
|
||||
cap_add:
|
||||
- audit_control
|
||||
labels:
|
||||
- docker_bench_security
|
||||
net: host
|
||||
pid: host
|
||||
stdin_open: true
|
||||
tty: true
|
||||
volumes:
|
||||
- /var/lib:/var/lib
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- /usr/lib/systemd:/usr/lib/systemd
|
||||
- /etc:/etc
|
||||
cap_add:
|
||||
- audit_control
|
||||
labels:
|
||||
- docker_bench_security
|
||||
pid: host
|
||||
stdin_open: true
|
||||
tty: true
|
||||
volumes:
|
||||
- /var/lib:/var/lib:ro
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
- /usr/lib/systemd:/usr/lib/systemd:ro
|
||||
- /etc:/etc:ro
|
||||
|
|
571
functions/functions_lib.sh
Normal file
571
functions/functions_lib.sh
Normal file
|
@ -0,0 +1,571 @@
|
|||
#!/bin/sh
|
||||
|
||||
host_configuration() {
|
||||
check_1
|
||||
check_1_1
|
||||
check_1_1_1
|
||||
check_1_1_2
|
||||
check_1_1_3
|
||||
check_1_1_4
|
||||
check_1_1_5
|
||||
check_1_1_6
|
||||
check_1_1_7
|
||||
check_1_1_8
|
||||
check_1_1_9
|
||||
check_1_1_10
|
||||
check_1_1_11
|
||||
check_1_1_12
|
||||
check_1_1_13
|
||||
check_1_1_14
|
||||
check_1_1_15
|
||||
check_1_1_16
|
||||
check_1_1_17
|
||||
check_1_1_18
|
||||
check_1_2
|
||||
check_1_2_1
|
||||
check_1_2_2
|
||||
check_1_end
|
||||
}
|
||||
|
||||
host_configuration_level1() {
|
||||
check_1
|
||||
check_1_end
|
||||
}
|
||||
|
||||
linux_hosts_specific_configuration() {
|
||||
check_1_1
|
||||
check_1_1_1
|
||||
check_1_1_2
|
||||
check_1_1_3
|
||||
check_1_1_4
|
||||
check_1_1_5
|
||||
check_1_1_6
|
||||
check_1_1_7
|
||||
check_1_1_8
|
||||
check_1_1_9
|
||||
check_1_1_10
|
||||
check_1_1_11
|
||||
check_1_1_12
|
||||
check_1_1_13
|
||||
check_1_1_14
|
||||
check_1_1_15
|
||||
check_1_1_16
|
||||
check_1_1_17
|
||||
check_1_1_18
|
||||
}
|
||||
|
||||
host_general_configuration() {
|
||||
check_1
|
||||
check_1_2
|
||||
check_1_2_1
|
||||
check_1_2_2
|
||||
check_1_end
|
||||
}
|
||||
|
||||
docker_daemon_configuration() {
|
||||
check_2
|
||||
check_2_1
|
||||
check_2_2
|
||||
check_2_3
|
||||
check_2_4
|
||||
check_2_5
|
||||
check_2_6
|
||||
check_2_7
|
||||
check_2_8
|
||||
check_2_9
|
||||
check_2_10
|
||||
check_2_11
|
||||
check_2_12
|
||||
check_2_13
|
||||
check_2_14
|
||||
check_2_15
|
||||
check_2_16
|
||||
check_2_17
|
||||
check_2_18
|
||||
check_2_end
|
||||
}
|
||||
|
||||
docker_daemon_configuration_level1() {
|
||||
check_2
|
||||
check_2_end
|
||||
}
|
||||
|
||||
docker_daemon_files() {
|
||||
check_3
|
||||
check_3_1
|
||||
check_3_2
|
||||
check_3_3
|
||||
check_3_4
|
||||
check_3_5
|
||||
check_3_6
|
||||
check_3_7
|
||||
check_3_8
|
||||
check_3_9
|
||||
check_3_10
|
||||
check_3_11
|
||||
check_3_12
|
||||
check_3_13
|
||||
check_3_14
|
||||
check_3_15
|
||||
check_3_16
|
||||
check_3_17
|
||||
check_3_18
|
||||
check_3_19
|
||||
check_3_20
|
||||
check_3_21
|
||||
check_3_22
|
||||
check_3_23
|
||||
check_3_24
|
||||
check_3_end
|
||||
}
|
||||
|
||||
docker_daemon_files_level1() {
|
||||
check_3
|
||||
check_3_end
|
||||
}
|
||||
|
||||
container_images() {
|
||||
check_4
|
||||
check_4_1
|
||||
check_4_2
|
||||
check_4_3
|
||||
check_4_4
|
||||
check_4_5
|
||||
check_4_6
|
||||
check_4_7
|
||||
check_4_8
|
||||
check_4_9
|
||||
check_4_10
|
||||
check_4_11
|
||||
check_4_12
|
||||
check_4_end
|
||||
}
|
||||
|
||||
container_images_level1() {
|
||||
check_4
|
||||
check_4_end
|
||||
}
|
||||
|
||||
container_runtime() {
|
||||
check_5
|
||||
check_running_containers
|
||||
check_5_1
|
||||
check_5_2
|
||||
check_5_3
|
||||
check_5_4
|
||||
check_5_5
|
||||
check_5_6
|
||||
check_5_7
|
||||
check_5_8
|
||||
check_5_9
|
||||
check_5_10
|
||||
check_5_11
|
||||
check_5_12
|
||||
check_5_13
|
||||
check_5_14
|
||||
check_5_15
|
||||
check_5_16
|
||||
check_5_17
|
||||
check_5_18
|
||||
check_5_19
|
||||
check_5_20
|
||||
check_5_21
|
||||
check_5_22
|
||||
check_5_23
|
||||
check_5_24
|
||||
check_5_25
|
||||
check_5_26
|
||||
check_5_27
|
||||
check_5_28
|
||||
check_5_29
|
||||
check_5_30
|
||||
check_5_31
|
||||
check_5_32
|
||||
check_5_end
|
||||
}
|
||||
|
||||
container_runtime_level1() {
|
||||
check_5
|
||||
check_5_end
|
||||
}
|
||||
|
||||
docker_security_operations() {
|
||||
check_6
|
||||
check_6_1
|
||||
check_6_2
|
||||
check_6_end
|
||||
}
|
||||
|
||||
docker_security_operations_level1() {
|
||||
check_6
|
||||
check_6_1
|
||||
check_6_2
|
||||
check_6_end
|
||||
}
|
||||
|
||||
docker_swarm_configuration() {
|
||||
check_7
|
||||
check_7_1
|
||||
check_7_2
|
||||
check_7_3
|
||||
check_7_4
|
||||
check_7_5
|
||||
check_7_6
|
||||
check_7_7
|
||||
check_7_8
|
||||
check_7_9
|
||||
check_7_end
|
||||
}
|
||||
|
||||
docker_swarm_configuration_level1() {
|
||||
check_7
|
||||
check_7_end
|
||||
}
|
||||
|
||||
docker_enterprise_configuration() {
|
||||
check_8
|
||||
check_product_license
|
||||
check_8_1
|
||||
check_8_1_1
|
||||
check_8_1_2
|
||||
check_8_1_3
|
||||
check_8_1_4
|
||||
check_8_1_5
|
||||
check_8_1_6
|
||||
check_8_1_7
|
||||
check_8_2
|
||||
check_8_2_1
|
||||
check_8_end
|
||||
}
|
||||
|
||||
docker_enterprise_configuration_level1() {
|
||||
check_8
|
||||
check_product_license
|
||||
check_8_1
|
||||
check_8_1_1
|
||||
check_8_1_2
|
||||
check_8_1_3
|
||||
check_8_1_4
|
||||
check_8_1_5
|
||||
check_8_1_6
|
||||
check_8_1_7
|
||||
check_8_2
|
||||
check_8_2_1
|
||||
check_8_end
|
||||
}
|
||||
|
||||
universal_control_plane_configuration() {
|
||||
check_8
|
||||
check_8_1
|
||||
check_8_1_1
|
||||
check_8_1_2
|
||||
check_8_1_3
|
||||
check_8_1_4
|
||||
check_8_1_5
|
||||
check_8_1_6
|
||||
check_8_1_7
|
||||
check_8_end
|
||||
}
|
||||
|
||||
docker_trusted_registry_configuration() {
|
||||
check_8
|
||||
check_8_2
|
||||
check_8_2_1
|
||||
check_8_end
|
||||
}
|
||||
|
||||
community_checks() {
|
||||
check_c
|
||||
check_c_1
|
||||
check_c_1_1
|
||||
check_c_2
|
||||
check_c_5_3_1
|
||||
check_c_5_3_2
|
||||
check_c_5_3_3
|
||||
check_c_5_3_4
|
||||
check_c_end
|
||||
}
|
||||
|
||||
# CIS
|
||||
cis() {
|
||||
host_configuration
|
||||
docker_daemon_configuration
|
||||
docker_daemon_files
|
||||
container_images
|
||||
container_runtime
|
||||
docker_security_operations
|
||||
docker_swarm_configuration
|
||||
}
|
||||
|
||||
cis_level1() {
|
||||
host_configuration_level1
|
||||
docker_daemon_configuration_level1
|
||||
docker_daemon_files_level1
|
||||
container_images_level1
|
||||
container_runtime_level1
|
||||
docker_security_operations_level1
|
||||
docker_swarm_configuration_level1
|
||||
}
|
||||
|
||||
cis_controls_v8_ig1() {
|
||||
check_1_1_2
|
||||
check_1_1_3
|
||||
check_2_1
|
||||
check_2_13
|
||||
check_2_14
|
||||
check_3_1
|
||||
check_3_2
|
||||
check_3_3
|
||||
check_3_4
|
||||
check_3_5
|
||||
check_3_6
|
||||
check_3_7
|
||||
check_3_8
|
||||
check_3_9
|
||||
check_3_10
|
||||
check_3_11
|
||||
check_3_12
|
||||
check_3_13
|
||||
check_3_14
|
||||
check_3_15
|
||||
check_3_16
|
||||
check_3_17
|
||||
check_3_18
|
||||
check_3_19
|
||||
check_3_20
|
||||
check_3_21
|
||||
check_3_22
|
||||
check_3_23
|
||||
check_3_24
|
||||
check_4_8
|
||||
check_4_11
|
||||
check_5_5
|
||||
check_5_14
|
||||
check_5_18
|
||||
check_5_22
|
||||
check_5_23
|
||||
check_5_24
|
||||
check_5_25
|
||||
check_5_26
|
||||
check_5_32
|
||||
check_7_2
|
||||
check_7_6
|
||||
check_7_7
|
||||
check_7_8
|
||||
}
|
||||
|
||||
cis_controls_v8_ig2() {
|
||||
check_1_1_1
|
||||
check_1_1_2
|
||||
check_1_1_3
|
||||
check_1_1_4
|
||||
check_1_1_5
|
||||
check_1_1_6
|
||||
check_1_1_7
|
||||
check_1_1_8
|
||||
check_1_1_9
|
||||
check_1_1_10
|
||||
check_1_1_11
|
||||
check_1_1_12
|
||||
check_1_1_13
|
||||
check_1_1_14
|
||||
check_1_1_15
|
||||
check_1_1_16
|
||||
check_1_1_17
|
||||
check_1_1_18
|
||||
check_1_2_1
|
||||
check_1_2_2
|
||||
check_2_1
|
||||
check_2_2
|
||||
check_2_3
|
||||
check_2_4
|
||||
check_2_5
|
||||
check_2_7
|
||||
check_2_8
|
||||
check_2_11
|
||||
check_2_13
|
||||
check_2_14
|
||||
check_2_15
|
||||
check_2_16
|
||||
check_2_18
|
||||
check_3_1
|
||||
check_3_2
|
||||
check_3_3
|
||||
check_3_4
|
||||
check_3_5
|
||||
check_3_6
|
||||
check_3_7
|
||||
check_3_8
|
||||
check_3_9
|
||||
check_3_10
|
||||
check_3_11
|
||||
check_3_12
|
||||
check_3_13
|
||||
check_3_14
|
||||
check_3_15
|
||||
check_3_16
|
||||
check_3_17
|
||||
check_3_18
|
||||
check_3_19
|
||||
check_3_20
|
||||
check_3_21
|
||||
check_3_22
|
||||
check_3_23
|
||||
check_3_24
|
||||
check_4_2
|
||||
check_4_3
|
||||
check_4_4
|
||||
check_4_7
|
||||
check_4_8
|
||||
check_4_9
|
||||
check_4_11
|
||||
check_5_1
|
||||
check_5_2
|
||||
check_5_3
|
||||
check_5_4
|
||||
check_5_5
|
||||
check_5_7
|
||||
check_5_10
|
||||
check_5_11
|
||||
check_5_12
|
||||
check_5_14
|
||||
check_5_16
|
||||
check_5_17
|
||||
check_5_18
|
||||
check_5_19
|
||||
check_5_21
|
||||
check_5_22
|
||||
check_5_23
|
||||
check_5_24
|
||||
check_5_25
|
||||
check_5_26
|
||||
check_5_27
|
||||
check_5_30
|
||||
check_5_31
|
||||
check_5_32
|
||||
check_6_1
|
||||
check_6_2
|
||||
check_7_2
|
||||
check_7_3
|
||||
check_7_5
|
||||
check_7_6
|
||||
check_7_7
|
||||
check_7_8
|
||||
check_7_9
|
||||
}
|
||||
|
||||
cis_controls_v8_ig3() {
|
||||
check_1_1_1
|
||||
check_1_1_2
|
||||
check_1_1_3
|
||||
check_1_1_4
|
||||
check_1_1_5
|
||||
check_1_1_6
|
||||
check_1_1_7
|
||||
check_1_1_8
|
||||
check_1_1_9
|
||||
check_1_1_10
|
||||
check_1_1_11
|
||||
check_1_1_12
|
||||
check_1_1_13
|
||||
check_1_1_14
|
||||
check_1_1_15
|
||||
check_1_1_16
|
||||
check_1_1_17
|
||||
check_1_1_18
|
||||
check_1_2_1
|
||||
check_1_2_2
|
||||
check_2_1
|
||||
check_2_2
|
||||
check_2_3
|
||||
check_2_4
|
||||
check_2_5
|
||||
check_2_7
|
||||
check_2_8
|
||||
check_2_11
|
||||
check_2_13
|
||||
check_2_14
|
||||
check_2_15
|
||||
check_2_16
|
||||
check_2_18
|
||||
check_3_1
|
||||
check_3_2
|
||||
check_3_3
|
||||
check_3_4
|
||||
check_3_5
|
||||
check_3_6
|
||||
check_3_7
|
||||
check_3_8
|
||||
check_3_9
|
||||
check_3_10
|
||||
check_3_11
|
||||
check_3_12
|
||||
check_3_13
|
||||
check_3_14
|
||||
check_3_15
|
||||
check_3_16
|
||||
check_3_17
|
||||
check_3_18
|
||||
check_3_19
|
||||
check_3_20
|
||||
check_3_21
|
||||
check_3_22
|
||||
check_3_23
|
||||
check_3_24
|
||||
check_4_2
|
||||
check_4_3
|
||||
check_4_4
|
||||
check_4_6
|
||||
check_4_7
|
||||
check_4_8
|
||||
check_4_9
|
||||
check_4_11
|
||||
check_4_12
|
||||
check_5_1
|
||||
check_5_2
|
||||
check_5_3
|
||||
check_5_4
|
||||
check_5_5
|
||||
check_5_7
|
||||
check_5_8
|
||||
check_5_9
|
||||
check_5_10
|
||||
check_5_11
|
||||
check_5_12
|
||||
check_5_14
|
||||
check_5_16
|
||||
check_5_17
|
||||
check_5_18
|
||||
check_5_19
|
||||
check_5_21
|
||||
check_5_22
|
||||
check_5_23
|
||||
check_5_24
|
||||
check_5_25
|
||||
check_5_26
|
||||
check_5_27
|
||||
check_5_30
|
||||
check_5_31
|
||||
check_5_32
|
||||
check_6_1
|
||||
check_6_2
|
||||
check_7_2
|
||||
check_7_3
|
||||
check_7_5
|
||||
check_7_6
|
||||
check_7_7
|
||||
check_7_8
|
||||
check_7_9
|
||||
}
|
||||
|
||||
# Community contributed
|
||||
community() {
|
||||
community_checks
|
||||
}
|
||||
|
||||
# All
|
||||
all() {
|
||||
cis
|
||||
docker_enterprise_configuration
|
||||
community
|
||||
}
|
163
functions/helper_lib.sh
Normal file
163
functions/helper_lib.sh
Normal file
|
@ -0,0 +1,163 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Returns the absolute path of a given string
|
||||
abspath () { case "$1" in /*)printf "%s\n" "$1";; *)printf "%s\n" "$PWD/$1";; esac; }
|
||||
|
||||
# Audit rules default path
|
||||
auditrules="/etc/audit/audit.rules"
|
||||
|
||||
# Check for required program(s)
|
||||
req_programs() {
|
||||
for p in $1; do
|
||||
command -v "$p" >/dev/null 2>&1 || { printf "Required program not found: %s\n" "$p"; exit 1; }
|
||||
done
|
||||
if command -v jq >/dev/null 2>&1; then
|
||||
HAVE_JQ=true
|
||||
else
|
||||
HAVE_JQ=false
|
||||
fi
|
||||
if command -v ss >/dev/null 2>&1; then
|
||||
netbin=ss
|
||||
return
|
||||
fi
|
||||
if command -v netstat >/dev/null 2>&1; then
|
||||
netbin=netstat
|
||||
return
|
||||
fi
|
||||
echo "ss or netstat command not found."
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Compares versions of software of the format X.Y.Z
|
||||
do_version_check() {
|
||||
[ "$1" = "$2" ] && return 10
|
||||
|
||||
ver1front=$(printf "%s" "$1" | cut -d "." -f -1)
|
||||
ver1back=$(printf "%s" "$1" | cut -d "." -f 2-)
|
||||
ver2front=$(printf "%s" "$2" | cut -d "." -f -1)
|
||||
ver2back=$(printf "%s" "$2" | cut -d "." -f 2-)
|
||||
|
||||
if [ "$ver1front" != "$1" ] || [ "$ver2front" != "$2" ]; then
|
||||
[ "$ver1front" -gt "$ver2front" ] && return 11
|
||||
[ "$ver1front" -lt "$ver2front" ] && return 9
|
||||
|
||||
[ "$ver1front" = "$1" ] || [ -z "$ver1back" ] && ver1back=0
|
||||
[ "$ver2front" = "$2" ] || [ -z "$ver2back" ] && ver2back=0
|
||||
do_version_check "$ver1back" "$ver2back"
|
||||
return $?
|
||||
fi
|
||||
[ "$1" -gt "$2" ] && return 11 || return 9
|
||||
}
|
||||
|
||||
# Extracts commandline args from the newest running processes named like the first parameter
|
||||
get_command_line_args() {
|
||||
PROC="$1"
|
||||
|
||||
for PID in $(pgrep -f -n "$PROC"); do
|
||||
tr "\0" " " < /proc/"$PID"/cmdline
|
||||
done
|
||||
}
|
||||
|
||||
# Extract the cumulative command line arguments for the docker daemon
|
||||
#
|
||||
# If specified multiple times, all matches are returned.
|
||||
# Accounts for long and short variants, call with short option.
|
||||
# Does not account for option defaults or implicit options.
|
||||
get_docker_cumulative_command_line_args() {
|
||||
OPTION="$1"
|
||||
|
||||
line_arg="dockerd"
|
||||
if ! get_command_line_args "docker daemon" >/dev/null 2>&1 ; then
|
||||
line_arg="docker daemon"
|
||||
fi
|
||||
|
||||
get_command_line_args "$line_arg" |
|
||||
# normalize known long options to their short versions
|
||||
sed \
|
||||
-e 's/\-\-debug/-D/g' \
|
||||
-e 's/\-\-host/-H/g' \
|
||||
-e 's/\-\-log-level/-l/g' \
|
||||
-e 's/\-\-version/-v/g' \
|
||||
|
|
||||
# normalize parameters separated by space(s) to -O=VALUE
|
||||
sed \
|
||||
-e 's/\-\([DHlv]\)[= ]\([^- ][^ ]\)/-\1=\2/g' \
|
||||
|
|
||||
# get the last interesting option
|
||||
tr ' ' "\n" |
|
||||
grep "^${OPTION}" |
|
||||
# normalize quoting of values
|
||||
sed \
|
||||
-e 's/"//g' \
|
||||
-e "s/'//g"
|
||||
}
|
||||
|
||||
# Extract the effective command line arguments for the docker daemon
|
||||
#
|
||||
# Accounts for multiple specifications, takes the last option.
|
||||
# Accounts for long and short variants, call with short option
|
||||
# Does not account for option default or implicit options.
|
||||
get_docker_effective_command_line_args() {
|
||||
OPTION="$1"
|
||||
get_docker_cumulative_command_line_args "$OPTION" | tail -n1
|
||||
}
|
||||
|
||||
get_docker_configuration_file() {
|
||||
FILE="$(get_docker_effective_command_line_args '--config-file' | \
|
||||
sed 's/.*=//g')"
|
||||
|
||||
if [ -f "$FILE" ]; then
|
||||
CONFIG_FILE="$FILE"
|
||||
return
|
||||
fi
|
||||
if [ -f '/etc/docker/daemon.json' ]; then
|
||||
CONFIG_FILE='/etc/docker/daemon.json'
|
||||
return
|
||||
fi
|
||||
CONFIG_FILE='/dev/null'
|
||||
}
|
||||
|
||||
get_docker_configuration_file_args() {
|
||||
OPTION="$1"
|
||||
|
||||
get_docker_configuration_file
|
||||
|
||||
if "$HAVE_JQ"; then
|
||||
jq --monochrome-output --raw-output "if has(\"${OPTION}\") then .[\"${OPTION}\"] else \"\" end" "$CONFIG_FILE"
|
||||
else
|
||||
cat "$CONFIG_FILE" | tr , '\n' | grep "$OPTION" | sed 's/.*://g' | tr -d '" ',
|
||||
fi
|
||||
}
|
||||
|
||||
get_service_file() {
|
||||
SERVICE="$1"
|
||||
|
||||
if [ -f "/etc/systemd/system/$SERVICE" ]; then
|
||||
echo "/etc/systemd/system/$SERVICE"
|
||||
return
|
||||
fi
|
||||
if [ -f "/lib/systemd/system/$SERVICE" ]; then
|
||||
echo "/lib/systemd/system/$SERVICE"
|
||||
return
|
||||
fi
|
||||
if find /run -name "$SERVICE" 2> /dev/null 1>&2; then
|
||||
find /run -name "$SERVICE" | head -n1
|
||||
return
|
||||
fi
|
||||
if [ "$(systemctl show -p FragmentPath "$SERVICE" | sed 's/.*=//')" != "" ]; then
|
||||
systemctl show -p FragmentPath "$SERVICE" | sed 's/.*=//'
|
||||
return
|
||||
fi
|
||||
echo "/usr/lib/systemd/system/$SERVICE"
|
||||
}
|
||||
|
||||
yell_info() {
|
||||
yell "# --------------------------------------------------------------------------------------------
|
||||
# Docker Bench for Security v$version
|
||||
#
|
||||
# Docker, Inc. (c) 2015-$(date +"%Y")
|
||||
#
|
||||
# Checks for dozens of common best-practices around deploying Docker containers in production.
|
||||
# Based on the CIS Docker Benchmark 1.6.0.
|
||||
# --------------------------------------------------------------------------------------------"
|
||||
}
|
190
functions/output_lib.sh
Normal file
190
functions/output_lib.sh
Normal file
|
@ -0,0 +1,190 @@
|
|||
#!/bin/bash
|
||||
|
||||
bldred='\033[1;31m' # Bold Red
|
||||
bldgrn='\033[1;32m' # Bold Green
|
||||
bldblu='\033[1;34m' # Bold Blue
|
||||
bldylw='\033[1;33m' # Bold Yellow
|
||||
txtrst='\033[0m'
|
||||
|
||||
if [ -n "$nocolor" ] && [ "$nocolor" = "nocolor" ]; then
|
||||
bldred=''
|
||||
bldgrn=''
|
||||
bldblu=''
|
||||
bldylw=''
|
||||
txtrst=''
|
||||
fi
|
||||
|
||||
logit () {
|
||||
printf "%b\n" "$1" | tee -a "$logger"
|
||||
}
|
||||
|
||||
info () {
|
||||
local infoCountCheck
|
||||
local OPTIND c
|
||||
while getopts c args
|
||||
do
|
||||
case $args in
|
||||
c) infoCountCheck="true" ;;
|
||||
*) exit 1 ;;
|
||||
esac
|
||||
done
|
||||
if [ "$infoCountCheck" = "true" ]; then
|
||||
printf "%b\n" "${bldblu}[INFO]${txtrst} $2" | tee -a "$logger"
|
||||
totalChecks=$((totalChecks + 1))
|
||||
return
|
||||
fi
|
||||
printf "%b\n" "${bldblu}[INFO]${txtrst} $1" | tee -a "$logger"
|
||||
}
|
||||
|
||||
pass () {
|
||||
local passScored
|
||||
local passCountCheck
|
||||
local OPTIND s c
|
||||
while getopts sc args
|
||||
do
|
||||
case $args in
|
||||
s) passScored="true" ;;
|
||||
c) passCountCheck="true" ;;
|
||||
*) exit 1 ;;
|
||||
esac
|
||||
done
|
||||
if [ "$passScored" = "true" ] || [ "$passCountCheck" = "true" ]; then
|
||||
printf "%b\n" "${bldgrn}[PASS]${txtrst} $2" | tee -a "$logger"
|
||||
totalChecks=$((totalChecks + 1))
|
||||
fi
|
||||
if [ "$passScored" = "true" ]; then
|
||||
currentScore=$((currentScore + 1))
|
||||
fi
|
||||
if [ "$passScored" != "true" ] && [ "$passCountCheck" != "true" ]; then
|
||||
printf "%b\n" "${bldgrn}[PASS]${txtrst} $1" | tee -a "$logger"
|
||||
fi
|
||||
}
|
||||
|
||||
warn () {
|
||||
local warnScored
|
||||
local OPTIND s
|
||||
while getopts s args
|
||||
do
|
||||
case $args in
|
||||
s) warnScored="true" ;;
|
||||
*) exit 1 ;;
|
||||
esac
|
||||
done
|
||||
if [ "$warnScored" = "true" ]; then
|
||||
printf "%b\n" "${bldred}[WARN]${txtrst} $2" | tee -a "$logger"
|
||||
totalChecks=$((totalChecks + 1))
|
||||
currentScore=$((currentScore - 1))
|
||||
return
|
||||
fi
|
||||
printf "%b\n" "${bldred}[WARN]${txtrst} $1" | tee -a "$logger"
|
||||
}
|
||||
|
||||
note () {
|
||||
local noteCountCheck
|
||||
local OPTIND c
|
||||
while getopts c args
|
||||
do
|
||||
case $args in
|
||||
c) noteCountCheck="true" ;;
|
||||
*) exit 1 ;;
|
||||
esac
|
||||
done
|
||||
if [ "$noteCountCheck" = "true" ]; then
|
||||
printf "%b\n" "${bldylw}[NOTE]${txtrst} $2" | tee -a "$logger"
|
||||
totalChecks=$((totalChecks + 1))
|
||||
return
|
||||
fi
|
||||
printf "%b\n" "${bldylw}[NOTE]${txtrst} $1" | tee -a "$logger"
|
||||
}
|
||||
|
||||
yell () {
|
||||
printf "%b\n" "${bldylw}$1${txtrst}\n"
|
||||
}
|
||||
|
||||
beginjson () {
|
||||
printf "{\n \"dockerbenchsecurity\": \"%s\",\n \"start\": %s,\n \"tests\": [" "$1" "$2" | tee "$logger.json" 2>/dev/null 1>&2
|
||||
}
|
||||
|
||||
endjson (){
|
||||
printf "\n ],\n \"checks\": %s,\n \"score\": %s,\n \"end\": %s\n}" "$1" "$2" "$3" | tee -a "$logger.json" 2>/dev/null 1>&2
|
||||
}
|
||||
|
||||
logjson (){
|
||||
printf "\n \"%s\": \"%s\"," "$1" "$2" | tee -a "$logger.json" 2>/dev/null 1>&2
|
||||
}
|
||||
|
||||
SSEP=
|
||||
SEP=
|
||||
startsectionjson() {
|
||||
printf "%s\n {\n \"id\": \"%s\",\n \"desc\": \"%s\",\n \"results\": [" "$SSEP" "$1" "$2" | tee -a "$logger.json" 2>/dev/null 1>&2
|
||||
SEP=
|
||||
SSEP=","
|
||||
}
|
||||
|
||||
endsectionjson() {
|
||||
printf "\n ]\n }" | tee -a "$logger.json" 2>/dev/null 1>&2
|
||||
}
|
||||
|
||||
starttestjson() {
|
||||
printf "%s\n {\n \"id\": \"%s\",\n \"desc\": \"%s\",\n " "$SEP" "$1" "$2" | tee -a "$logger.json" 2>/dev/null 1>&2
|
||||
SEP=","
|
||||
}
|
||||
|
||||
log_to_json() {
|
||||
if [ $# -eq 1 ]; then
|
||||
printf "\"result\": \"%s\"" "$1" | tee -a "$logger.json" 2>/dev/null 1>&2
|
||||
return
|
||||
fi
|
||||
if [ $# -eq 2 ] && [ $# -ne 1 ]; then
|
||||
# Result also contains details
|
||||
printf "\"result\": \"%s\",\n \"details\": \"%s\"" "$1" "$2" | tee -a "$logger.json" 2>/dev/null 1>&2
|
||||
return
|
||||
fi
|
||||
# Result also includes details and a list of items. Add that directly to details and to an array property "items"
|
||||
# Also limit the number of items to $limit, if $limit is non-zero
|
||||
truncItems=$3
|
||||
if [ "$limit" != 0 ]; then
|
||||
truncItems=""
|
||||
ITEM_COUNT=0
|
||||
for item in $3; do
|
||||
truncItems="$truncItems $item"
|
||||
ITEM_COUNT=$((ITEM_COUNT + 1));
|
||||
if [ "$ITEM_COUNT" == "$limit" ]; then
|
||||
truncItems="$truncItems (truncated)"
|
||||
break;
|
||||
fi
|
||||
done
|
||||
fi
|
||||
itemsJson=$(printf "[\n "; ISEP=""; ITEMCOUNT=0; for item in $truncItems; do printf "%s\"%s\"" "$ISEP" "$item"; ISEP=","; done; printf "\n ]")
|
||||
printf "\"result\": \"%s\",\n \"details\": \"%s: %s\",\n \"items\": %s" "$1" "$2" "$truncItems" "$itemsJson" | tee -a "$logger.json" 2>/dev/null 1>&2
|
||||
}
|
||||
|
||||
logcheckresult() {
|
||||
# Log to JSON
|
||||
log_to_json "$@"
|
||||
|
||||
# Log remediation measure to JSON
|
||||
if [ -n "$remediation" ] && [ "$1" != "PASS" ] && [ "$printremediation" = "1" ]; then
|
||||
printf ",\n \"remediation\": \"%s\"" "$remediation" | tee -a "$logger.json" 2>/dev/null 1>&2
|
||||
if [ -n "$remediationImpact" ]; then
|
||||
printf ",\n \"remediation-impact\": \"%s\"" "$remediationImpact" | tee -a "$logger.json" 2>/dev/null 1>&2
|
||||
fi
|
||||
fi
|
||||
printf "\n }" | tee -a "$logger.json" 2>/dev/null 1>&2
|
||||
|
||||
# Save remediation measure for print log to stdout
|
||||
if [ -n "$remediation" ] && [ "$1" != "PASS" ]; then
|
||||
if [ -n "${checkHeader}" ]; then
|
||||
if [ -n "${addSpaceHeader}" ]; then
|
||||
globalRemediation="${globalRemediation}\n"
|
||||
fi
|
||||
globalRemediation="${globalRemediation}\n${bldblu}[INFO]${txtrst} ${checkHeader}"
|
||||
checkHeader=""
|
||||
addSpaceHeader="1"
|
||||
fi
|
||||
globalRemediation="${globalRemediation}\n${bldblu}[INFO]${txtrst} ${id} - ${remediation}"
|
||||
if [ -n "${remediationImpact}" ]; then
|
||||
globalRemediation="${globalRemediation} Remediation Impact: ${remediationImpact}"
|
||||
fi
|
||||
fi
|
||||
}
|
105
helper_lib.sh
105
helper_lib.sh
|
@ -1,105 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Returns the absolute path of a given string
|
||||
abspath () { case "$1" in /*)printf "%s\n" "$1";; *)printf "%s\n" "$PWD/$1";; esac; }
|
||||
|
||||
# Compares versions of software of the format X.Y.Z
|
||||
do_version_check() {
|
||||
[ "$1" = "$2" ] && return 10
|
||||
|
||||
ver1front=$(printf "%s" "$1" | cut -d "." -f -1)
|
||||
ver1back=$(printf "%s" "$1" | cut -d "." -f 2-)
|
||||
ver2front=$(printf "%s" "$2" | cut -d "." -f -1)
|
||||
ver2back=$(printf "%s" "$2" | cut -d "." -f 2-)
|
||||
|
||||
if [ "$ver1front" != "$1" ] || [ "$ver2front" != "$2" ]; then
|
||||
[ "$ver1front" -gt "$ver2front" ] && return 11
|
||||
[ "$ver1front" -lt "$ver2front" ] && return 9
|
||||
|
||||
[ "$ver1front" = "$1" ] || [ -z "$ver1back" ] && ver1back=0
|
||||
[ "$ver2front" = "$2" ] || [ -z "$ver2back" ] && ver2back=0
|
||||
do_version_check "$ver1back" "$ver2back"
|
||||
return $?
|
||||
else
|
||||
[ "$1" -gt "$2" ] && return 11 || return 9
|
||||
fi
|
||||
}
|
||||
|
||||
# Compares two strings and returns 0 if the second is a substring of the first
|
||||
contains() {
|
||||
string="$1"
|
||||
substring="$2"
|
||||
if [ "${string#*$substring}" != "$string" ]
|
||||
then
|
||||
return 0 # $substring is in $string
|
||||
else
|
||||
return 1 # $substring is not in $string
|
||||
fi
|
||||
}
|
||||
|
||||
# Extracts commandline args from the newest running processes named like the first parameter
|
||||
get_command_line_args() {
|
||||
PROC="$1"
|
||||
|
||||
for PID in $(pgrep -f -n "$PROC")
|
||||
do
|
||||
tr "\0" " " < /proc/"$PID"/cmdline
|
||||
done
|
||||
}
|
||||
|
||||
# Extract the cumulative command line arguments for the docker daemon
|
||||
#
|
||||
# If specified multiple times, all matches are returned.
|
||||
# Accounts for long and short variants, call with short option.
|
||||
# Does not account for option defaults or implicit options.
|
||||
get_docker_cumulative_command_line_args() {
|
||||
OPTION="$1"
|
||||
|
||||
if ! get_command_line_args "docker daemon" >/dev/null 2>&1 ; then
|
||||
line_arg="docker daemon"
|
||||
else
|
||||
line_arg="dockerd"
|
||||
fi
|
||||
|
||||
get_command_line_args "$line_arg" |
|
||||
# normalize known long options to their short versions
|
||||
sed \
|
||||
-e 's/\-\-debug/-D/g' \
|
||||
-e 's/\-\-host/-H/g' \
|
||||
-e 's/\-\-log-level/-l/g' \
|
||||
-e 's/\-\-version/-v/g' \
|
||||
|
|
||||
# normalize parameters separated by space(s) to -O=VALUE
|
||||
sed \
|
||||
-e 's/\-\([DHlv]\)[= ]\([^- ][^ ]\)/-\1=\2/g' \
|
||||
|
|
||||
# get the last interesting option
|
||||
tr ' ' "\n" |
|
||||
grep "^${OPTION}" |
|
||||
# normalize quoting of values
|
||||
sed \
|
||||
-e 's/"//g' \
|
||||
-e "s/'//g"
|
||||
}
|
||||
|
||||
# Extract the effective command line arguments for the docker daemon
|
||||
#
|
||||
# Accounts for multiple specifications, takes the last option.
|
||||
# Accounts for long and short variants, call with short option
|
||||
# Does not account for option default or implicit options.
|
||||
get_docker_effective_command_line_args() {
|
||||
OPTION="$1"
|
||||
get_docker_cumulative_command_line_args $OPTION | tail -n1
|
||||
}
|
||||
|
||||
get_systemd_service_file(){
|
||||
SERVICE="$1"
|
||||
|
||||
if [ -f "/etc/systemd/system/$SERVICE" ]; then
|
||||
echo "/etc/systemd/system/$SERVICE"
|
||||
elif systemctl show -p FragmentPath "$SERVICE" 2> /dev/null 1>&2; then
|
||||
systemctl show -p FragmentPath "$SERVICE" | sed 's/.*=//'
|
||||
else
|
||||
echo "/usr/lib/systemd/system/$SERVICE"
|
||||
fi
|
||||
}
|
BIN
img/benchmark_log.png
Normal file
BIN
img/benchmark_log.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 346 KiB |
|
@ -1,26 +0,0 @@
|
|||
#!/bin/sh
|
||||
bldred='\033[1;31m'
|
||||
bldgrn='\033[1;32m'
|
||||
bldblu='\033[1;34m'
|
||||
bldylw='\033[1;33m' # Yellow
|
||||
txtrst='\033[0m'
|
||||
|
||||
logit () {
|
||||
printf "%b\n" "$1" | tee -a "$logger"
|
||||
}
|
||||
|
||||
info () {
|
||||
printf "%b\n" "${bldblu}[INFO]${txtrst} $1" | tee -a "$logger"
|
||||
}
|
||||
|
||||
pass () {
|
||||
printf "%b\n" "${bldgrn}[PASS]${txtrst} $1" | tee -a "$logger"
|
||||
}
|
||||
|
||||
warn () {
|
||||
printf "%b\n" "${bldred}[WARN]${txtrst} $1" | tee -a "$logger"
|
||||
}
|
||||
|
||||
yell () {
|
||||
printf "%b\n" "${bldylw}$1${txtrst}\n"
|
||||
}
|
|
@ -1,242 +1,662 @@
|
|||
#!/bin/sh
|
||||
#!/bin/bash
|
||||
|
||||
logit ""
|
||||
info "1 - Host Configuration"
|
||||
check_1() {
|
||||
logit ""
|
||||
local id="1"
|
||||
local desc="Host Configuration"
|
||||
checkHeader="$id - $desc"
|
||||
info "$checkHeader"
|
||||
startsectionjson "$id" "$desc"
|
||||
}
|
||||
|
||||
# 1.1
|
||||
check_1_1="1.1 - Create a separate partition for containers"
|
||||
grep /var/lib/docker /etc/fstab >/dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
pass "$check_1_1"
|
||||
else
|
||||
warn "$check_1_1"
|
||||
fi
|
||||
check_1_1() {
|
||||
local id="1.1"
|
||||
local desc="Linux Hosts Specific Configuration"
|
||||
local check="$id - $desc"
|
||||
info "$check"
|
||||
}
|
||||
|
||||
# 1.2
|
||||
check_1_2="1.2 - Use an updated Linux Kernel"
|
||||
kernel_version=$(uname -r | cut -d "-" -f 1)
|
||||
do_version_check 3.10 "$kernel_version"
|
||||
if [ $? -eq 11 ]; then
|
||||
warn "$check_1_2"
|
||||
else
|
||||
pass "$check_1_2"
|
||||
fi
|
||||
check_1_1_1() {
|
||||
local id="1.1.1"
|
||||
local desc="Ensure a separate partition for containers has been created (Automated)"
|
||||
local remediation="For new installations, you should create a separate partition for the /var/lib/docker mount point. For systems that have already been installed, you should use the Logical Volume Manager (LVM) within Linux to create a new partition."
|
||||
local remediationImpact="None."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
# 1.3
|
||||
check_1_3="1.3 - Harden the container host"
|
||||
info "$check_1_3"
|
||||
|
||||
# 1.4
|
||||
check_1_4="1.4 - Remove all non-essential services from the host - Network"
|
||||
# Check for listening network services.
|
||||
listening_services=$(netstat -na | grep -v tcp6 | grep -v unix | grep -c LISTEN)
|
||||
if [ "$listening_services" -eq 0 ]; then
|
||||
info "1.4 - Failed to get listening services for check: $check_1_4"
|
||||
else
|
||||
if [ "$listening_services" -gt 5 ]; then
|
||||
info "$check_1_4"
|
||||
info " * Host listening on: $listening_services ports"
|
||||
else
|
||||
pass "$check_1_4"
|
||||
docker_root_dir=$(docker info -f '{{ .DockerRootDir }}')
|
||||
if docker info | grep -q userns ; then
|
||||
docker_root_dir=$(readlink -f "$docker_root_dir/..")
|
||||
fi
|
||||
fi
|
||||
|
||||
# 1.5
|
||||
check_1_5="1.5 - Keep Docker up to date"
|
||||
docker_version=$(docker version | grep -i -A1 '^server' | grep -i 'version:' \
|
||||
| awk '{print $NF; exit}' | tr -d '[:alpha:]-,')
|
||||
docker_current_version="1.13.0"
|
||||
docker_current_date="2017-01-18"
|
||||
do_version_check "$docker_current_version" "$docker_version"
|
||||
if [ $? -eq 11 ]; then
|
||||
info "$check_1_5"
|
||||
info " * Using $docker_version, when $docker_current_version is current as of $docker_current_date"
|
||||
info " * Your operating system vendor may provide support and security maintenance for docker"
|
||||
else
|
||||
pass "$check_1_5"
|
||||
info " * Using $docker_version which is current as of $docker_current_date"
|
||||
info " * Check with your operating system vendor for support and security maintenance for docker"
|
||||
fi
|
||||
if mountpoint -q -- "$docker_root_dir" >/dev/null 2>&1; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
}
|
||||
|
||||
# 1.6
|
||||
check_1_6="1.6 - Only allow trusted users to control Docker daemon"
|
||||
docker_users=$(getent group docker)
|
||||
info "$check_1_6"
|
||||
for u in $docker_users; do
|
||||
info " * $u"
|
||||
done
|
||||
check_1_1_2() {
|
||||
local id="1.1.2"
|
||||
local desc="Ensure only trusted users are allowed to control Docker daemon (Automated)"
|
||||
local remediation="You should remove any untrusted users from the docker group using command sudo gpasswd -d <your-user> docker or add trusted users to the docker group using command sudo usermod -aG docker <your-user>. You should not create a mapping of sensitive directories from the host to container volumes."
|
||||
local remediationImpact="Only trust user are allow to build and execute containers as normal user."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
# 1.7
|
||||
check_1_7="1.7 - Audit docker daemon - /usr/bin/docker"
|
||||
file="/usr/bin/docker"
|
||||
command -v auditctl >/dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
auditctl -l | grep "$file" >/dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
pass "$check_1_7"
|
||||
docker_users=$(grep 'docker' /etc/group)
|
||||
if command -v getent >/dev/null 2>&1; then
|
||||
docker_users=$(getent group docker)
|
||||
fi
|
||||
docker_users=$(printf "%s" "$docker_users" | awk -F: '{print $4}')
|
||||
|
||||
local doubtfulusers=""
|
||||
if [ -n "$dockertrustusers" ]; then
|
||||
for u in $(printf "%s" "$docker_users" | sed "s/,/ /g"); do
|
||||
if ! printf "%s" "$dockertrustusers" | grep -q "$u" ; then
|
||||
doubtfulusers="$u"
|
||||
if [ -n "${doubtfulusers}" ]; then
|
||||
doubtfulusers="${doubtfulusers},$u"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
else
|
||||
warn "$check_1_7"
|
||||
info -c "$check"
|
||||
info " * Users: $docker_users"
|
||||
logcheckresult "INFO" "doubtfulusers" "$docker_users"
|
||||
fi
|
||||
else
|
||||
warn "1.7 - Failed to inspect: auditctl command not found."
|
||||
fi
|
||||
|
||||
# 1.8
|
||||
check_1_8="1.8 - Audit Docker files and directories - /var/lib/docker"
|
||||
directory="/var/lib/docker"
|
||||
if [ -d "$directory" ]; then
|
||||
command -v auditctl >/dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
auditctl -l | grep $directory >/dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
pass "$check_1_8"
|
||||
else
|
||||
warn "$check_1_8"
|
||||
if [ -n "${doubtfulusers}" ]; then
|
||||
warn -s "$check"
|
||||
warn " * Doubtful users: $doubtfulusers"
|
||||
logcheckresult "WARN" "doubtfulusers" "$doubtfulusers"
|
||||
fi
|
||||
|
||||
if [ -z "${doubtfulusers}" ] && [ -n "${dockertrustusers}" ]; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
fi
|
||||
}
|
||||
|
||||
check_1_1_3() {
|
||||
local id="1.1.3"
|
||||
local desc="Ensure auditing is configured for the Docker daemon (Automated)"
|
||||
local remediation="Install auditd. Add -w /usr/bin/dockerd -k docker to the /etc/audit/rules.d/audit.rules file. Then restart the audit daemon using command service auditd restart."
|
||||
local remediationImpact="Audit can generate large log files. So you need to make sure that they are rotated and archived periodically. Create a separate partition for audit logs to avoid filling up other critical partitions."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
file="/usr/bin/dockerd"
|
||||
if command -v auditctl >/dev/null 2>&1; then
|
||||
if auditctl -l | grep "$file" >/dev/null 2>&1; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
else
|
||||
warn "1.8 - Failed to inspect: auditctl command not found."
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
return
|
||||
fi
|
||||
else
|
||||
info "$check_1_8"
|
||||
info " * Directory not found"
|
||||
fi
|
||||
if grep -s "$file" "$auditrules" | grep "^[^#;]" 2>/dev/null 1>&2; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
}
|
||||
|
||||
# 1.9
|
||||
check_1_9="1.9 - Audit Docker files and directories - /etc/docker"
|
||||
directory="/etc/docker"
|
||||
if [ -d "$directory" ]; then
|
||||
command -v auditctl >/dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
auditctl -l | grep $directory >/dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
pass "$check_1_9"
|
||||
else
|
||||
warn "$check_1_9"
|
||||
fi
|
||||
else
|
||||
warn "1.9 - Failed to inspect: auditctl command not found."
|
||||
fi
|
||||
else
|
||||
info "$check_1_9"
|
||||
info " * Directory not found"
|
||||
fi
|
||||
check_1_1_4() {
|
||||
local id="1.1.4"
|
||||
local desc="Ensure auditing is configured for Docker files and directories -/run/containerd (Automated)"
|
||||
local remediation="Install auditd. Add -a exit,always -F path=/run/containerd -F perm=war -k docker to the /etc/audit/rules.d/audit.rules file. Then restart the audit daemon using command service auditd restart."
|
||||
local remediationImpact="Audit can generate large log files. So you need to make sure that they are rotated and archived periodically. Create a separate partition for audit logs to avoid filling up other critical partitions."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
# 1.10
|
||||
check_1_10="1.10 - Audit Docker files and directories - docker.service"
|
||||
file="$(get_systemd_service_file docker.service)"
|
||||
if [ -f "$file" ]; then
|
||||
command -v auditctl >/dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
auditctl -l | grep "$file" >/dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
pass "$check_1_10"
|
||||
else
|
||||
warn "$check_1_10"
|
||||
file="/run/containerd"
|
||||
if command -v auditctl >/dev/null 2>&1; then
|
||||
if auditctl -l | grep "$file" >/dev/null 2>&1; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
else
|
||||
warn "1.10 - Failed to inspect: auditctl command not found."
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
return
|
||||
fi
|
||||
else
|
||||
info "$check_1_10"
|
||||
info " * File not found"
|
||||
fi
|
||||
if grep -s "$file" "$auditrules" | grep "^[^#;]" 2>/dev/null 1>&2; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
}
|
||||
|
||||
# 1.11
|
||||
check_1_11="1.11 - Audit Docker files and directories - docker.socket"
|
||||
file="$(get_systemd_service_file docker.socket)"
|
||||
if [ -e "$file" ]; then
|
||||
command -v auditctl >/dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
auditctl -l | grep "$file" >/dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
pass "$check_1_11"
|
||||
else
|
||||
warn "$check_1_11"
|
||||
fi
|
||||
else
|
||||
warn "1.11 - Failed to inspect: auditctl command not found."
|
||||
fi
|
||||
else
|
||||
info "$check_1_11"
|
||||
info " * File not found"
|
||||
fi
|
||||
check_1_1_5() {
|
||||
local id="1.1.5"
|
||||
local desc="Ensure auditing is configured for Docker files and directories - /var/lib/docker (Automated)"
|
||||
local remediation="Install auditd. Add -w /var/lib/docker -k docker to the /etc/audit/rules.d/audit.rules file. Then restart the audit daemon using command service auditd restart."
|
||||
local remediationImpact="Audit can generate large log files. So you need to make sure that they are rotated and archived periodically. Create a separate partition for audit logs to avoid filling up other critical partitions."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
# 1.12
|
||||
check_1_12="1.12 - Audit Docker files and directories - /etc/default/docker"
|
||||
file="/etc/default/docker"
|
||||
if [ -f "$file" ]; then
|
||||
command -v auditctl >/dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
auditctl -l | grep $file >/dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
pass "$check_1_12"
|
||||
else
|
||||
warn "$check_1_12"
|
||||
directory="/var/lib/docker"
|
||||
if [ -d "$directory" ]; then
|
||||
if command -v auditctl >/dev/null 2>&1; then
|
||||
if auditctl -l | grep $directory >/dev/null 2>&1; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
return
|
||||
fi
|
||||
else
|
||||
warn "1.12 - Failed to inspect: auditctl command not found."
|
||||
if grep -s "$directory" "$auditrules" | grep "^[^#;]" 2>/dev/null 1>&2; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
return
|
||||
fi
|
||||
else
|
||||
info "$check_1_12"
|
||||
info " * File not found"
|
||||
fi
|
||||
info -c "$check"
|
||||
info " * Directory not found"
|
||||
logcheckresult "INFO" "Directory not found"
|
||||
}
|
||||
|
||||
# 1.13
|
||||
check_1_13="1.13 - Audit Docker files and directories - /etc/docker/daemon.json"
|
||||
file="/etc/docker/daemon.json"
|
||||
if [ -f "$file" ]; then
|
||||
command -v auditctl >/dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
auditctl -l | grep $file >/dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
pass "$check_1_13"
|
||||
else
|
||||
warn "$check_1_13"
|
||||
fi
|
||||
else
|
||||
warn "1.13 - Failed to inspect: auditctl command not found."
|
||||
fi
|
||||
else
|
||||
info "$check_1_13"
|
||||
info " * File not found"
|
||||
fi
|
||||
check_1_1_6() {
|
||||
local id="1.1.6"
|
||||
local desc="Ensure auditing is configured for Docker files and directories - /etc/docker (Automated)"
|
||||
local remediation="Install auditd. Add -w /etc/docker -k docker to the /etc/audit/rules.d/audit.rules file. Then restart the audit daemon using command service auditd restart."
|
||||
local remediationImpact="Audit can generate large log files. So you need to make sure that they are rotated and archived periodically. Create a separate partition for audit logs to avoid filling up other critical partitions."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
# 1.14
|
||||
check_1_14="1.14 - Audit Docker files and directories - /usr/bin/docker-containerd"
|
||||
file="/usr/bin/docker-containerd"
|
||||
if [ -f "$file" ]; then
|
||||
command -v auditctl >/dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
auditctl -l | grep $file >/dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
pass "$check_1_14"
|
||||
else
|
||||
warn "$check_1_14"
|
||||
directory="/etc/docker"
|
||||
if [ -d "$directory" ]; then
|
||||
if command -v auditctl >/dev/null 2>&1; then
|
||||
if auditctl -l | grep $directory >/dev/null 2>&1; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
return
|
||||
fi
|
||||
else
|
||||
warn "1.14 - Failed to inspect: auditctl command not found."
|
||||
if grep -s "$directory" "$auditrules" | grep "^[^#;]" 2>/dev/null 1>&2; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
return
|
||||
fi
|
||||
else
|
||||
info "$check_1_14"
|
||||
info " * File not found"
|
||||
fi
|
||||
info -c "$check"
|
||||
info " * Directory not found"
|
||||
logcheckresult "INFO" "Directory not found"
|
||||
}
|
||||
|
||||
# 1.15
|
||||
check_1_15="1.15 - Audit Docker files and directories - /usr/bin/docker-runc"
|
||||
file="/usr/bin/docker-runc"
|
||||
if [ -f "$file" ]; then
|
||||
command -v auditctl >/dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
auditctl -l | grep $file >/dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
pass "$check_1_15"
|
||||
else
|
||||
warn "$check_1_15"
|
||||
check_1_1_7() {
|
||||
local id="1.1.7"
|
||||
local desc="Ensure auditing is configured for Docker files and directories - docker.service (Automated)"
|
||||
local remediation
|
||||
remediation="Install auditd. Add -w $(get_service_file docker.service) -k docker to the /etc/audit/rules.d/audit.rules file. Then restart the audit daemon using command service auditd restart."
|
||||
local remediationImpact="Audit can generate large log files. So you need to make sure that they are rotated and archived periodically. Create a separate partition for audit logs to avoid filling up other critical partitions."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
file="$(get_service_file docker.service)"
|
||||
if [ -f "$file" ]; then
|
||||
if command -v auditctl >/dev/null 2>&1; then
|
||||
if auditctl -l | grep "$file" >/dev/null 2>&1; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
return
|
||||
fi
|
||||
else
|
||||
warn "1.15 - Failed to inspect: auditctl command not found."
|
||||
if grep -s "$file" "$auditrules" | grep "^[^#;]" 2>/dev/null 1>&2; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
return
|
||||
fi
|
||||
else
|
||||
info "$check_1_15"
|
||||
info " * File not found"
|
||||
fi
|
||||
info -c "$check"
|
||||
info " * File not found"
|
||||
logcheckresult "INFO" "File not found"
|
||||
}
|
||||
|
||||
check_1_1_8() {
|
||||
local id="1.1.8"
|
||||
local desc="Ensure auditing is configured for Docker files and directories - containerd.sock (Automated)"
|
||||
local remediation
|
||||
remediation="Install auditd. Add -w $(get_service_file containerd.sock) -k docker to the /etc/audit/rules.d/audit.rules file. Then restart the audit daemon using command service auditd restart."
|
||||
local remediationImpact="Audit can generate large log files. So you need to make sure that they are rotated and archived periodically. Create a separate partition for audit logs to avoid filling up other critical partitions."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
file="$(get_service_file containerd.sock)"
|
||||
if [ -e "$file" ]; then
|
||||
if command -v auditctl >/dev/null 2>&1; then
|
||||
if auditctl -l | grep "$file" >/dev/null 2>&1; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
return
|
||||
fi
|
||||
if grep -s "$file" "$auditrules" | grep "^[^#;]" 2>/dev/null 1>&2; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
return
|
||||
fi
|
||||
info -c "$check"
|
||||
info " * File not found"
|
||||
logcheckresult "INFO" "File not found"
|
||||
}
|
||||
check_1_1_9() {
|
||||
local id="1.1.9"
|
||||
local desc="Ensure auditing is configured for Docker files and directories - docker.socket (Automated)"
|
||||
local remediation
|
||||
remediation="Install auditd. Add -w $(get_service_file docker.socket) -k docker to the /etc/audit/rules.d/audit.rules file. Then restart the audit daemon using command service auditd restart."
|
||||
local remediationImpact="Audit can generate large log files. So you need to make sure that they are rotated and archived periodically. Create a separate partition for audit logs to avoid filling up other critical partitions."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
file="$(get_service_file docker.socket)"
|
||||
if [ -e "$file" ]; then
|
||||
if command -v auditctl >/dev/null 2>&1; then
|
||||
if auditctl -l | grep "$file" >/dev/null 2>&1; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
return
|
||||
fi
|
||||
if grep -s "$file" "$auditrules" | grep "^[^#;]" 2>/dev/null 1>&2; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
return
|
||||
fi
|
||||
info -c "$check"
|
||||
info " * File not found"
|
||||
logcheckresult "INFO" "File not found"
|
||||
}
|
||||
|
||||
check_1_1_10() {
|
||||
local id="1.1.10"
|
||||
local desc="Ensure auditing is configured for Docker files and directories - /etc/default/docker (Automated)"
|
||||
local remediation="Install auditd. Add -w /etc/default/docker -k docker to the /etc/audit/rules.d/audit.rules file. Then restart the audit daemon using command service auditd restart."
|
||||
local remediationImpact="Audit can generate large log files. So you need to make sure that they are rotated and archived periodically. Create a separate partition for audit logs to avoid filling up other critical partitions."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
file="/etc/default/docker"
|
||||
if [ -f "$file" ]; then
|
||||
if command -v auditctl >/dev/null 2>&1; then
|
||||
if auditctl -l | grep $file >/dev/null 2>&1; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
return
|
||||
fi
|
||||
if grep -s "$file" "$auditrules" | grep "^[^#;]" 2>/dev/null 1>&2; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
return
|
||||
fi
|
||||
info -c "$check"
|
||||
info " * File not found"
|
||||
logcheckresult "INFO" "File not found"
|
||||
}
|
||||
|
||||
check_1_1_11() {
|
||||
local id="1.1.11"
|
||||
local desc="Ensure auditing is configured for Dockerfiles and directories - /etc/docker/daemon.json (Automated)"
|
||||
local remediation="Install auditd. Add -w /etc/docker/daemon.json -k docker to the /etc/audit/rules.d/audit.rules file. Then restart the audit daemon using command service auditd restart."
|
||||
local remediationImpact="Audit can generate large log files. So you need to make sure that they are rotated and archived periodically. Create a separate partition for audit logs to avoid filling up other critical partitions."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
file="/etc/docker/daemon.json"
|
||||
if [ -f "$file" ]; then
|
||||
if command -v auditctl >/dev/null 2>&1; then
|
||||
if auditctl -l | grep $file >/dev/null 2>&1; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
return
|
||||
fi
|
||||
if grep -s "$file" "$auditrules" | grep "^[^#;]" 2>/dev/null 1>&2; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
return
|
||||
fi
|
||||
info -c "$check"
|
||||
info " * File not found"
|
||||
logcheckresult "INFO" "File not found"
|
||||
}
|
||||
|
||||
check_1_1_12() {
|
||||
local id="1.1.12"
|
||||
local desc="1.1.12 Ensure auditing is configured for Dockerfiles and directories - /etc/containerd/config.toml (Automated)"
|
||||
local remediation="Install auditd. Add -w /etc/containerd/config.toml -k docker to the /etc/audit/rules.d/audit.rules file. Then restart the audit daemon using command service auditd restart."
|
||||
local remediationImpact="Audit can generate large log files. So you need to make sure that they are rotated and archived periodically. Create a separate partition for audit logs to avoid filling up other critical partitions."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
file="/etc/containerd/config.toml"
|
||||
if [ -f "$file" ]; then
|
||||
if command -v auditctl >/dev/null 2>&1; then
|
||||
if auditctl -l | grep $file >/dev/null 2>&1; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
return
|
||||
fi
|
||||
if grep -s "$file" "$auditrules" | grep "^[^#;]" 2>/dev/null 1>&2; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
return
|
||||
fi
|
||||
info -c "$check"
|
||||
info " * File not found"
|
||||
logcheckresult "INFO" "File not found"
|
||||
}
|
||||
|
||||
check_1_1_13() {
|
||||
local id="1.1.13"
|
||||
local desc="Ensure auditing is configured for Docker files and directories - /etc/sysconfig/docker (Automated)"
|
||||
local remediation="Install auditd. Add -w /etc/sysconfig/docker -k docker to the /etc/audit/rules.d/audit.rules file. Then restart the audit daemon using command service auditd restart."
|
||||
local remediationImpact="Audit can generate large log files. So you need to make sure that they are rotated and archived periodically. Create a separate partition for audit logs to avoid filling up other critical partitions."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
file="/etc/sysconfig/docker"
|
||||
if [ -f "$file" ]; then
|
||||
if command -v auditctl >/dev/null 2>&1; then
|
||||
if auditctl -l | grep $file >/dev/null 2>&1; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
return
|
||||
fi
|
||||
if grep -s "$file" "$auditrules" | grep "^[^#;]" 2>/dev/null 1>&2; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
return
|
||||
fi
|
||||
info -c "$check"
|
||||
info " * File not found"
|
||||
logcheckresult "INFO" "File not found"
|
||||
}
|
||||
|
||||
check_1_1_14() {
|
||||
local id="1.1.14"
|
||||
local desc="Ensure auditing is configured for Docker files and directories - /usr/bin/containerd (Automated)"
|
||||
local remediation="Install auditd. Add -w /usr/bin/containerd -k docker to the /etc/audit/rules.d/audit.rules file. Then restart the audit daemon using command service auditd restart."
|
||||
local remediationImpact="Audit can generate large log files. So you need to make sure that they are rotated and archived periodically. Create a separate partition for audit logs to avoid filling up other critical partitions."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
file="/usr/bin/containerd"
|
||||
if [ -f "$file" ]; then
|
||||
if command -v auditctl >/dev/null 2>&1; then
|
||||
if auditctl -l | grep $file >/dev/null 2>&1; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
return
|
||||
fi
|
||||
if grep -s "$file" "$auditrules" | grep "^[^#;]" 2>/dev/null 1>&2; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
return
|
||||
fi
|
||||
info -c "$check"
|
||||
info " * File not found"
|
||||
logcheckresult "INFO" "File not found"
|
||||
}
|
||||
|
||||
check_1_1_15() {
|
||||
local id="1.1.15"
|
||||
local desc="Ensure auditing is configured for Docker files and directories - /usr/bin/containerd-shim (Automated)"
|
||||
local remediation="Install auditd. Add -w /usr/bin/containerd-shim -k docker to the /etc/audit/rules.d/audit.rules file. Then restart the audit daemon using command service auditd restart."
|
||||
local remediationImpact="Audit can generate large log files. So you need to make sure that they are rotated and archived periodically. Create a separate partition for audit logs to avoid filling up other critical partitions."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
file="/usr/bin/containerd-shim"
|
||||
if [ -f "$file" ]; then
|
||||
if command -v auditctl >/dev/null 2>&1; then
|
||||
if auditctl -l | grep $file >/dev/null 2>&1; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
return
|
||||
fi
|
||||
if grep -s "$file" "$auditrules" | grep "^[^#;]" 2>/dev/null 1>&2; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
return
|
||||
fi
|
||||
info -c "$check"
|
||||
info " * File not found"
|
||||
logcheckresult "INFO" "File not found"
|
||||
}
|
||||
|
||||
check_1_1_16() {
|
||||
local id="1.1.16"
|
||||
local desc="Ensure auditing is configured for Docker files and directories - /usr/bin/containerd-shim-runc-v1 (Automated)"
|
||||
local remediation="Install auditd. Add -w /usr/bin/containerd-shim-runc-v1 -k docker to the /etc/audit/rules.d/audit.rules file. Then restart the audit daemon using command service auditd restart."
|
||||
local remediationImpact="Audit can generate large log files. So you need to make sure that they are rotated and archived periodically. Create a separate partition for audit logs to avoid filling up other critical partitions."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
file="/usr/bin/containerd-shim-runc-v1"
|
||||
if [ -f "$file" ]; then
|
||||
if command -v auditctl >/dev/null 2>&1; then
|
||||
if auditctl -l | grep $file >/dev/null 2>&1; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
return
|
||||
fi
|
||||
if grep -s "$file" "$auditrules" | grep "^[^#;]" 2>/dev/null 1>&2; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
return
|
||||
fi
|
||||
info -c "$check"
|
||||
info " * File not found"
|
||||
logcheckresult "INFO" "File not found"
|
||||
}
|
||||
|
||||
check_1_1_17() {
|
||||
local id="1.1.17"
|
||||
local desc="Ensure auditing is configured for Docker files and directories - /usr/bin/containerd-shim-runc-v2 (Automated)"
|
||||
local remediation="Install auditd. Add -w /usr/bin/containerd-shim-runc-v2 -k docker to the /etc/audit/rules.d/audit.rules file. Then restart the audit daemon using command service auditd restart."
|
||||
local remediationImpact="Audit can generate large log files. So you need to make sure that they are rotated and archived periodically. Create a separate partition for audit logs to avoid filling up other critical partitions."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
file="/usr/bin/containerd-shim-runc-v2"
|
||||
if [ -f "$file" ]; then
|
||||
if command -v auditctl >/dev/null 2>&1; then
|
||||
if auditctl -l | grep $file >/dev/null 2>&1; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
return
|
||||
fi
|
||||
if grep -s "$file" "$auditrules" | grep "^[^#;]" 2>/dev/null 1>&2; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
return
|
||||
fi
|
||||
info -c "$check"
|
||||
info " * File not found"
|
||||
logcheckresult "INFO" "File not found"
|
||||
}
|
||||
|
||||
check_1_1_18() {
|
||||
local id="1.1.18"
|
||||
local desc="Ensure auditing is configured for Docker files and directories - /usr/bin/runc (Automated)"
|
||||
local remediation="Install auditd. Add -w /usr/bin/runc -k docker to the /etc/audit/rules.d/audit.rules file. Then restart the audit daemon using command service auditd restart."
|
||||
local remediationImpact="Audit can generate large log files. So you need to make sure that they are rotated and archived periodically. Create a separate partition for audit logs to avoid filling up other critical partitions."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
file="/usr/bin/runc"
|
||||
if [ -f "$file" ]; then
|
||||
if command -v auditctl >/dev/null 2>&1; then
|
||||
if auditctl -l | grep $file >/dev/null 2>&1; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
return
|
||||
fi
|
||||
if grep -s "$file" "$auditrules" | grep "^[^#;]" 2>/dev/null 1>&2; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
return
|
||||
fi
|
||||
info -c "$check"
|
||||
info " * File not found"
|
||||
logcheckresult "INFO" "File not found"
|
||||
}
|
||||
|
||||
check_1_2() {
|
||||
local id="1.2"
|
||||
local desc="General Configuration"
|
||||
local check="$id - $desc"
|
||||
info "$check"
|
||||
}
|
||||
|
||||
check_1_2_1() {
|
||||
local id="1.2.1"
|
||||
local desc="Ensure the container host has been Hardened (Manual)"
|
||||
local remediation="You may consider various Security Benchmarks for your container host."
|
||||
local remediationImpact="None."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
note -c "$check"
|
||||
logcheckresult "INFO"
|
||||
}
|
||||
|
||||
check_1_2_2() {
|
||||
local id="1.2.2"
|
||||
local desc="Ensure that the version of Docker is up to date (Manual)"
|
||||
local remediation="You should monitor versions of Docker releases and make sure your software is updated as required."
|
||||
local remediationImpact="You should perform a risk assessment regarding Docker version updates and review how they may impact your operations."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
docker_version=$(docker version | grep -i -A2 '^server' | grep ' Version:' \
|
||||
| awk '{print $NF; exit}' | tr -d '[:alpha:]-,')
|
||||
docker_current_version="$(date +%y.%m.0 -d @$(( $(date +%s) - 2592000)))"
|
||||
do_version_check "$docker_current_version" "$docker_version"
|
||||
if [ $? -eq 11 ]; then
|
||||
pass -c "$check"
|
||||
info " * Using $docker_version, verify is it up to date as deemed necessary"
|
||||
logcheckresult "INFO" "Using $docker_version"
|
||||
return
|
||||
fi
|
||||
pass -c "$check"
|
||||
info " * Using $docker_version which is current"
|
||||
info " * Check with your operating system vendor for support and security maintenance for Docker"
|
||||
logcheckresult "PASS" "Using $docker_version"
|
||||
}
|
||||
|
||||
check_1_end() {
|
||||
endsectionjson
|
||||
}
|
||||
|
|
|
@ -1,196 +1,424 @@
|
|||
#!/bin/sh
|
||||
#!/bin/bash
|
||||
|
||||
logit "\n"
|
||||
info "2 - Docker Daemon Configuration"
|
||||
check_2() {
|
||||
logit ""
|
||||
local id="2"
|
||||
local desc="Docker daemon configuration"
|
||||
checkHeader="$id - $desc"
|
||||
info "$checkHeader"
|
||||
startsectionjson "$id" "$desc"
|
||||
}
|
||||
|
||||
# 2.1
|
||||
check_2_1="2.1 - Restrict network traffic between containers"
|
||||
get_docker_effective_command_line_args '--icc' | grep "false" >/dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
pass "$check_2_1"
|
||||
else
|
||||
warn "$check_2_1"
|
||||
fi
|
||||
check_2_1() {
|
||||
local id="2.1"
|
||||
local desc="Run the Docker daemon as a non-root user, if possible (Manual)"
|
||||
local remediation="Follow the current Dockerdocumentation on how to install the Docker daemon as a non-root user."
|
||||
local remediationImpact="There are multiple prerequisites depending on which distribution that is in use, and also known limitations regarding networking and resource limitation. Running in rootless mode also changes the location of any configuration files in use, including all containers using the daemon."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
# 2.2
|
||||
check_2_2="2.2 - Set the logging level"
|
||||
get_docker_effective_command_line_args '-l' >/dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
get_docker_effective_command_line_args '-l' | grep "info" >/dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
pass "$check_2_2"
|
||||
else
|
||||
warn "$check_2_2"
|
||||
note -c "$check"
|
||||
logcheckresult "INFO"
|
||||
}
|
||||
|
||||
check_2_2() {
|
||||
local id="2.2"
|
||||
local desc="Ensure network traffic is restricted between containers on the default bridge (Scored)"
|
||||
local remediation="Edit the Docker daemon configuration file to ensure that inter-container communication is disabled: icc: false."
|
||||
local remediationImpact="Inter-container communication is disabled on the default network bridge. If any communication between containers on the same host is desired, it needs to be explicitly defined using container linking or custom networks."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
if get_docker_effective_command_line_args '--icc' | grep false >/dev/null 2>&1; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
else
|
||||
pass "$check_2_2"
|
||||
fi
|
||||
if [[ $(get_docker_configuration_file_args 'icc' | grep "false") ]] && [[ $(get_docker_configuration_file_args 'icc' | grep "false") != "null" ]] ; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
}
|
||||
|
||||
# 2.3
|
||||
check_2_3="2.3 - Allow Docker to make changes to iptables"
|
||||
get_docker_effective_command_line_args '--iptables' | grep "false" >/dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
warn "$check_2_3"
|
||||
else
|
||||
pass "$check_2_3"
|
||||
fi
|
||||
check_2_3() {
|
||||
local id="2.3"
|
||||
local desc="Ensure the logging level is set to 'info' (Scored)"
|
||||
local remediation="Ensure that the Docker daemon configuration file has the following configuration included log-level: info. Alternatively, run the Docker daemon as following: dockerd --log-level=info"
|
||||
local remediationImpact="None."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
# 2.4
|
||||
check_2_4="2.4 - Do not use insecure registries"
|
||||
get_docker_effective_command_line_args '--insecure-registry' | grep "insecure-registry" >/dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
warn "$check_2_4"
|
||||
else
|
||||
pass "$check_2_4"
|
||||
fi
|
||||
|
||||
# 2.5
|
||||
check_2_5="2.5 - Do not use the aufs storage driver"
|
||||
docker info 2>/dev/null | grep -e "^Storage Driver:\s*aufs\s*$" >/dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
warn "$check_2_5"
|
||||
else
|
||||
pass "$check_2_5"
|
||||
fi
|
||||
|
||||
# 2.6
|
||||
check_2_6="2.6 - Configure TLS authentication for Docker daemon"
|
||||
get_docker_cumulative_command_line_args '-H' | grep -vE '(unix|fd)://' >/dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
get_docker_cumulative_command_line_args '--tlskey' | grep 'tlskey=' >/dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
get_docker_cumulative_command_line_args '--tlsverify' | grep 'tlsverify' >/dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
pass "$check_2_6"
|
||||
#pass " * Docker daemon currently listening on TCP with TLS and verification"
|
||||
else
|
||||
warn "$check_2_6"
|
||||
warn " * Docker daemon currently listening on TCP with TLS, but no verification"
|
||||
if get_docker_configuration_file_args 'log-level' >/dev/null 2>&1; then
|
||||
if get_docker_configuration_file_args 'log-level' | grep info >/dev/null 2>&1; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
else
|
||||
warn "$check_2_6"
|
||||
if [ -z "$(get_docker_configuration_file_args 'log-level')" ]; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
return
|
||||
fi
|
||||
if get_docker_effective_command_line_args '-l'; then
|
||||
if get_docker_effective_command_line_args '-l' | grep "info" >/dev/null 2>&1; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
return
|
||||
fi
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
}
|
||||
|
||||
check_2_4() {
|
||||
local id="2.4"
|
||||
local desc="Ensure Docker is allowed to make changes to iptables (Scored)"
|
||||
local remediation="Do not run the Docker daemon with --iptables=false option."
|
||||
local remediationImpact="The Docker daemon service requires iptables rules to be enabled before it starts."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
if get_docker_effective_command_line_args '--iptables' | grep "false" >/dev/null 2>&1; then
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
return
|
||||
fi
|
||||
if [[ $(get_docker_configuration_file_args 'iptables' | grep "false") ]] && [[ $(get_docker_configuration_file_args 'iptables' | grep "false") != "null" ]] ; then
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
return
|
||||
fi
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
}
|
||||
|
||||
check_2_5() {
|
||||
local id="2.5"
|
||||
local desc="Ensure insecure registries are not used (Scored)"
|
||||
local remediation="You should ensure that no insecure registries are in use."
|
||||
local remediationImpact="None."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
if get_docker_effective_command_line_args '--insecure-registry' | grep "insecure-registry" >/dev/null 2>&1; then
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
return
|
||||
fi
|
||||
if [[ $(get_docker_configuration_file_args 'insecure-registries' | grep -v '\[]') ]] && [[ $(get_docker_configuration_file_args 'insecure-registries' | grep -v '\[]') != "null" ]] ; then
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
return
|
||||
fi
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
}
|
||||
|
||||
check_2_6() {
|
||||
local id="2.6"
|
||||
local desc="Ensure aufs storage driver is not used (Scored)"
|
||||
local remediation="Do not start Docker daemon as using dockerd --storage-driver aufs option."
|
||||
local remediationImpact="aufs is the only storage driver that allows containers to share executable and shared library memory. Its use should be reviewed in line with your organization's security policy."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
if docker info 2>/dev/null | grep -e "^\sStorage Driver:\s*aufs\s*$" >/dev/null 2>&1; then
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
return
|
||||
fi
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
}
|
||||
|
||||
check_2_7() {
|
||||
local id="2.7"
|
||||
local desc="Ensure TLS authentication for Docker daemon is configured (Scored)"
|
||||
local remediation="Follow the steps mentioned in the Docker documentation or other references. By default, TLS authentication is not configured."
|
||||
local remediationImpact="You would need to manage and guard certificates and keys for the Docker daemon and Docker clients."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
if $(grep -qE "host.*tcp://" "$CONFIG_FILE") || \
|
||||
[ $(get_docker_cumulative_command_line_args '-H' | grep -vE '(unix|fd)://') > /dev/null 2>&1 ]; then
|
||||
if [ $(get_docker_configuration_file_args '"tlsverify":' | grep 'true') ] || \
|
||||
[ $(get_docker_cumulative_command_line_args '--tlsverify' | grep 'tlsverify') >/dev/null 2>&1 ]; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
if [ $(get_docker_configuration_file_args '"tls":' | grep 'true') ] || \
|
||||
[ $(get_docker_cumulative_command_line_args '--tls' | grep 'tls$') >/dev/null 2>&1 ]; then
|
||||
warn -s "$check"
|
||||
warn " * Docker daemon currently listening on TCP with TLS, but no verification"
|
||||
logcheckresult "WARN" "Docker daemon currently listening on TCP with TLS, but no verification"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
warn " * Docker daemon currently listening on TCP without TLS"
|
||||
logcheckresult "WARN" "Docker daemon currently listening on TCP without TLS"
|
||||
return
|
||||
fi
|
||||
else
|
||||
info "$check_2_6"
|
||||
info -c "$check"
|
||||
info " * Docker daemon not listening on TCP"
|
||||
fi
|
||||
logcheckresult "INFO" "Docker daemon not listening on TCP"
|
||||
}
|
||||
|
||||
check_2_8() {
|
||||
local id="2.8"
|
||||
local desc="Ensure the default ulimit is configured appropriately (Manual)"
|
||||
local remediation="Run Docker in daemon mode and pass --default-ulimit as option with respective ulimits as appropriate in your environment and in line with your security policy. Example: dockerd --default-ulimit nproc=1024:2048 --default-ulimit nofile=100:200"
|
||||
local remediationImpact="If ulimits are set incorrectly this could cause issues with system resources, possibly causing a denial of service condition."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
# 2.7
|
||||
check_2_7="2.7 - Set default ulimit as appropriate"
|
||||
get_docker_effective_command_line_args '--default-ulimit' | grep "default-ulimit" >/dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
pass "$check_2_7"
|
||||
else
|
||||
info "$check_2_7"
|
||||
if [[ $(get_docker_configuration_file_args 'default-ulimits' | grep -v '{}') ]] && [[ $(get_docker_configuration_file_args 'default-ulimits' | grep -v '{}') != "null" ]] ; then
|
||||
pass -c "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
if get_docker_effective_command_line_args '--default-ulimit' | grep "default-ulimit" >/dev/null 2>&1; then
|
||||
pass -c "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
info -c "$check"
|
||||
info " * Default ulimit doesn't appear to be set"
|
||||
fi
|
||||
logcheckresult "INFO" "Default ulimit doesn't appear to be set"
|
||||
}
|
||||
|
||||
# 2.8
|
||||
check_2_8="2.8 - Enable user namespace support"
|
||||
get_docker_effective_command_line_args '--userns-remap' | grep "userns-remap" >/dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
pass "$check_2_8"
|
||||
else
|
||||
warn "$check_2_8"
|
||||
fi
|
||||
check_2_9() {
|
||||
local id="2.9"
|
||||
local desc="Enable user namespace support (Scored)"
|
||||
local remediation="Please consult the Docker documentation for various ways in which this can be configured depending upon your requirements. The high-level steps are: Ensure that the files /etc/subuid and /etc/subgid exist. Start the docker daemon with --userns-remap flag."
|
||||
local remediationImpact="User namespace remapping is incompatible with a number of Docker features and also currently breaks some of its functionalities."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
# 2.9
|
||||
check_2_9="2.9 - Confirm default cgroup usage"
|
||||
get_docker_effective_command_line_args '--cgroup-parent' | grep "cgroup-parent" >/dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
info "$check_2_9"
|
||||
info " * Confirm cgroup usage"
|
||||
else
|
||||
pass "$check_2_9"
|
||||
fi
|
||||
|
||||
# 2.10
|
||||
check_2_10="2.10 - Do not change base device size until needed"
|
||||
get_docker_effective_command_line_args '--storage-opt' | grep "dm.basesize" >/dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
warn "$check_2_10"
|
||||
else
|
||||
pass "$check_2_10"
|
||||
fi
|
||||
|
||||
# 2.11
|
||||
check_2_11="2.11 - Use authorization plugin"
|
||||
get_docker_effective_command_line_args '--authorization-plugin' | grep "authorization-plugin" >/dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
pass "$check_2_11"
|
||||
else
|
||||
warn "$check_2_11"
|
||||
fi
|
||||
|
||||
# 2.12
|
||||
check_2_12="2.12 - Configure centralized and remote logging"
|
||||
get_docker_effective_command_line_args '--log-driver' | grep "log-driver" >/dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
pass "$check_2_12"
|
||||
else
|
||||
warn "$check_2_12"
|
||||
fi
|
||||
|
||||
# 2.13
|
||||
check_2_13="2.13 - Disable operations on legacy registry (v1)"
|
||||
get_docker_effective_command_line_args '--disable-legacy-registry' | grep "disable-legacy-registry" >/dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
pass "$check_2_13"
|
||||
else
|
||||
warn "$check_2_13"
|
||||
fi
|
||||
|
||||
# 2.14
|
||||
check_2_14="2.14 - Enable live restore"
|
||||
get_docker_effective_command_line_args '--live-restore' 2>/dev/null | grep "live-restore" >/dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
pass "$check_2_14"
|
||||
else
|
||||
if docker info 2>/dev/null | grep -e "Swarm:\s*active\s*" >/dev/null 2>&1; then
|
||||
pass "$check_2_14 (Incompatible with swarm mode)"
|
||||
else
|
||||
warn "$check_2_14"
|
||||
if [[ $(get_docker_configuration_file_args 'userns-remap' | grep -v '""') ]] && [[ $(get_docker_configuration_file_args 'userns-remap' | grep -v '""') != "null" ]] ; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
fi
|
||||
|
||||
# 2.15
|
||||
check_2_15="2.15 - Do not enable swarm mode, if not needed"
|
||||
docker info 2>/dev/null | grep -e "Swarm:\s*active\s*" >/dev/null 2>&1
|
||||
if [ $? -eq 1 ]; then
|
||||
pass "$check_2_15"
|
||||
else
|
||||
warn "$check_2_15"
|
||||
fi
|
||||
|
||||
# 2.16
|
||||
check_2_16="2.16 - Control the number of manager nodes in a swarm"
|
||||
if docker info 2>/dev/null | grep -e "Swarm:\s*active\s*" >/dev/null 2>&1; then
|
||||
managernodes=$(docker node ls | grep "Leader" | wc -l)
|
||||
if [ $managernodes -le 1 ]; then
|
||||
pass "$check_2_16"
|
||||
else
|
||||
warn "$check_2_16"
|
||||
if get_docker_effective_command_line_args '--userns-remap' | grep "userns-remap" >/dev/null 2>&1; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
else
|
||||
pass "$check_2_16 (Swarm mode not enabled)"
|
||||
fi
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
}
|
||||
|
||||
# 2.17
|
||||
check_2_17="2.17 - Bind swarm services to a specific host interface"
|
||||
netstat -lt | grep -e '\[::]:2377' -e '*:2377' -e '0.0.0.0:2377' >/dev/null 2>&1
|
||||
if [ $? -eq 1 ]; then
|
||||
pass "$check_2_17"
|
||||
else
|
||||
warn "$check_2_17"
|
||||
fi
|
||||
check_2_10() {
|
||||
local id="2.10"
|
||||
local desc="Ensure the default cgroup usage has been confirmed (Scored)"
|
||||
local remediation="The default setting is in line with good security practice and can be left in situ."
|
||||
local remediationImpact="None."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
# 2.18
|
||||
check_2_18="2.18 - Disable Userland Proxy"
|
||||
get_docker_effective_command_line_args '--userland-proxy=false' 2>/dev/null | grep "userland-proxy=false" >/dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
pass "$check_2_18"
|
||||
else
|
||||
warn "$check_2_18"
|
||||
fi
|
||||
if get_docker_configuration_file_args 'cgroup-parent' | grep -v ''; then
|
||||
warn -s "$check"
|
||||
info " * Confirm cgroup usage"
|
||||
logcheckresult "WARN" "Confirm cgroup usage"
|
||||
return
|
||||
fi
|
||||
if get_docker_effective_command_line_args '--cgroup-parent' | grep "cgroup-parent" >/dev/null 2>&1; then
|
||||
warn -s "$check"
|
||||
info " * Confirm cgroup usage"
|
||||
logcheckresult "WARN" "Confirm cgroup usage"
|
||||
return
|
||||
fi
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
}
|
||||
|
||||
check_2_11() {
|
||||
local id="2.11"
|
||||
local desc="Ensure base device size is not changed until needed (Scored)"
|
||||
local remediation="Do not set --storage-opt dm.basesize until needed."
|
||||
local remediationImpact="None."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
if get_docker_configuration_file_args 'storage-opts' | grep "dm.basesize" >/dev/null 2>&1; then
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
return
|
||||
fi
|
||||
if get_docker_effective_command_line_args '--storage-opt' | grep "dm.basesize" >/dev/null 2>&1; then
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
return
|
||||
fi
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
}
|
||||
|
||||
check_2_12() {
|
||||
local id="2.12"
|
||||
local desc="Ensure that authorization for Docker client commands is enabled (Scored)"
|
||||
local remediation="Install/Create an authorization plugin. Configure the authorization policy as desired. Start the docker daemon using command dockerd --authorization-plugin=<PLUGIN_ID>"
|
||||
local remediationImpact="Each Docker command needs to pass through the authorization plugin mechanism. This may have a performance impact"
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
if [[ $(get_docker_configuration_file_args 'authorization-plugins' | grep -v '\[]') ]] && [[ $(get_docker_configuration_file_args 'authorization-plugins' | grep -v '\[]') != "null" ]] ; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
if get_docker_effective_command_line_args '--authorization-plugin' | grep "authorization-plugin" >/dev/null 2>&1; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
}
|
||||
|
||||
check_2_13() {
|
||||
local id="2.13"
|
||||
local desc="Ensure centralized and remote logging is configured (Scored)"
|
||||
local remediation="Set up the desired log driver following its documentation. Start the docker daemon using that logging driver. Example: dockerd --log-driver=syslog --log-opt syslog-address=tcp://192.xxx.xxx.xxx"
|
||||
local remediationImpact="None."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
if docker info --format '{{ .LoggingDriver }}' | grep 'json-file' >/dev/null 2>&1; then
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
return
|
||||
fi
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
}
|
||||
|
||||
check_2_14() {
|
||||
local id="2.14"
|
||||
local desc="Ensure containers are restricted from acquiring new privileges (Scored)"
|
||||
local remediation="You should run the Docker daemon using command: dockerd --no-new-privileges"
|
||||
local remediationImpact="no_new_priv prevents LSMs such as SELinux from escalating the privileges of individual containers."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
if get_docker_effective_command_line_args '--no-new-privileges' | grep "no-new-privileges" >/dev/null 2>&1; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
if get_docker_configuration_file_args 'no-new-privileges' | grep true >/dev/null 2>&1; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
}
|
||||
|
||||
check_2_15() {
|
||||
local id="2.15"
|
||||
local desc="Ensure live restore is enabled (Scored)"
|
||||
local remediation="Run Docker in daemon mode and pass --live-restore option."
|
||||
local remediationImpact="None."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
if docker info 2>/dev/null | grep -e "Live Restore Enabled:\s*true\s*" >/dev/null 2>&1; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
if docker info 2>/dev/null | grep -e "Swarm:*\sactive\s*" >/dev/null 2>&1; then
|
||||
pass -s "$check (Incompatible with swarm mode)"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
if get_docker_effective_command_line_args '--live-restore' | grep "live-restore" >/dev/null 2>&1; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
}
|
||||
|
||||
check_2_16() {
|
||||
local id="2.16"
|
||||
local desc="Ensure Userland Proxy is Disabled (Scored)"
|
||||
local remediation="You should run the Docker daemon using command: dockerd --userland-proxy=false"
|
||||
local remediationImpact="Some systems with older Linux kernels may not be able to support hairpin NAT and therefore require the userland proxy service. Also, some networking setups can be impacted by the removal of the userland proxy."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
if get_docker_configuration_file_args 'userland-proxy' | grep false >/dev/null 2>&1; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
if get_docker_effective_command_line_args '--userland-proxy=false' 2>/dev/null | grep "userland-proxy=false" >/dev/null 2>&1; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
}
|
||||
|
||||
check_2_17() {
|
||||
local id="2.17"
|
||||
local desc="Ensure that a daemon-wide custom seccomp profile is applied if appropriate (Manual)"
|
||||
local remediation="By default, Docker's default seccomp profile is applied. If this is adequate for your environment, no action is necessary."
|
||||
local remediationImpact="A misconfigured seccomp profile could possibly interrupt your container environment. You should therefore exercise extreme care if you choose to override the default settings."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
if docker info --format '{{ .SecurityOptions }}' | grep 'name=seccomp,profile=default' 2>/dev/null 1>&2; then
|
||||
pass -c "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
info -c "$check"
|
||||
logcheckresult "INFO"
|
||||
}
|
||||
|
||||
check_2_18() {
|
||||
docker_version=$(docker version | grep -i -A2 '^server' | grep ' Version:' \
|
||||
| awk '{print $NF; exit}' | tr -d '[:alpha:]-,.' | cut -c 1-4)
|
||||
|
||||
local id="2.18"
|
||||
local desc="Ensure that experimental features are not implemented in production (Scored)"
|
||||
local remediation="You should not pass --experimental as a runtime parameter to the Docker daemon on production systems."
|
||||
local remediationImpact="None."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
if [ "$docker_version" -le 1903 ]; then
|
||||
if docker version -f '{{.Server.Experimental}}' | grep false 2>/dev/null 1>&2; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
return
|
||||
fi
|
||||
local desc="$desc (Deprecated)"
|
||||
local check="$id - $desc"
|
||||
info -c "$desc"
|
||||
logcheckresult "INFO"
|
||||
}
|
||||
|
||||
check_2_end() {
|
||||
endsectionjson
|
||||
}
|
||||
|
|
|
@ -1,324 +1,646 @@
|
|||
#!/bin/sh
|
||||
#!/bin/bash
|
||||
|
||||
logit "\n"
|
||||
info "3 - Docker Daemon Configuration Files"
|
||||
check_3() {
|
||||
logit ""
|
||||
local id="3"
|
||||
local desc="Docker daemon configuration files"
|
||||
checkHeader="$id - $desc"
|
||||
info "$checkHeader"
|
||||
startsectionjson "$id" "$desc"
|
||||
}
|
||||
|
||||
# 3.1
|
||||
check_3_1="3.1 - Verify that docker.service file ownership is set to root:root"
|
||||
file="$(get_systemd_service_file docker.service)"
|
||||
if [ -f "$file" ]; then
|
||||
if [ "$(stat -c %u%g $file)" -eq 00 ]; then
|
||||
pass "$check_3_1"
|
||||
else
|
||||
warn "$check_3_1"
|
||||
warn " * Wrong ownership for $file"
|
||||
fi
|
||||
else
|
||||
info "$check_3_1"
|
||||
info " * File not found"
|
||||
fi
|
||||
check_3_1() {
|
||||
local id="3.1"
|
||||
local desc="Ensure that the docker.service file ownership is set to root:root (Automated)"
|
||||
local remediation="Find out the file location: systemctl show -p FragmentPath docker.service. If the file does not exist, this recommendation is not applicable. If the file does exist, you should run the command chown root:root <path>, in order to set the ownership and group ownership for the file to root."
|
||||
local remediationImpact="None."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
# 3.2
|
||||
check_3_2="3.2 - Verify that docker.service file permissions are set to 644 or more restrictive"
|
||||
file="$(get_systemd_service_file docker.service)"
|
||||
if [ -f "$file" ]; then
|
||||
if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 600 ]; then
|
||||
pass "$check_3_2"
|
||||
else
|
||||
warn "$check_3_2"
|
||||
warn " * Wrong permissions for $file"
|
||||
fi
|
||||
else
|
||||
info "$check_3_2"
|
||||
info " * File not found"
|
||||
fi
|
||||
|
||||
# 3.3
|
||||
check_3_3="3.3 - Verify that docker.socket file ownership is set to root:root"
|
||||
file="$(get_systemd_service_file docker.socket)"
|
||||
if [ -f "$file" ]; then
|
||||
if [ "$(stat -c %u%g $file)" -eq 00 ]; then
|
||||
pass "$check_3_3"
|
||||
else
|
||||
warn "$check_3_3"
|
||||
warn " * Wrong ownership for $file"
|
||||
fi
|
||||
else
|
||||
info "$check_3_3"
|
||||
info " * File not found"
|
||||
fi
|
||||
|
||||
# 3.4
|
||||
check_3_4="3.4 - Verify that docker.socket file permissions are set to 644 or more restrictive"
|
||||
file="$(get_systemd_service_file docker.socket)"
|
||||
if [ -f "$file" ]; then
|
||||
if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 600 ]; then
|
||||
pass "$check_3_4"
|
||||
else
|
||||
warn "$check_3_4"
|
||||
warn " * Wrong permissions for $file"
|
||||
fi
|
||||
else
|
||||
info "$check_3_4"
|
||||
info " * File not found"
|
||||
fi
|
||||
|
||||
# 3.5
|
||||
check_3_5="3.5 - Verify that /etc/docker directory ownership is set to root:root"
|
||||
directory="/etc/docker"
|
||||
if [ -d "$directory" ]; then
|
||||
if [ "$(stat -c %u%g $directory)" -eq 00 ]; then
|
||||
pass "$check_3_5"
|
||||
else
|
||||
warn "$check_3_5"
|
||||
warn " * Wrong ownership for $directory"
|
||||
fi
|
||||
else
|
||||
info "$check_3_5"
|
||||
info " * Directory not found"
|
||||
fi
|
||||
|
||||
# 3.6
|
||||
check_3_6="3.6 - Verify that /etc/docker directory permissions are set to 755 or more restrictive"
|
||||
directory="/etc/docker"
|
||||
if [ -d "$directory" ]; then
|
||||
if [ "$(stat -c %a $directory)" -eq 755 ]; then
|
||||
pass "$check_3_6"
|
||||
elif [ "$(stat -c %a $directory)" -eq 700 ]; then
|
||||
pass "$check_3_6"
|
||||
else
|
||||
warn "$check_3_6"
|
||||
warn " * Wrong permissions for $directory"
|
||||
fi
|
||||
else
|
||||
info "$check_3_6"
|
||||
info " * Directory not found"
|
||||
fi
|
||||
|
||||
# 3.7
|
||||
check_3_7="3.7 - Verify that registry certificate file ownership is set to root:root"
|
||||
directory="/etc/docker/certs.d/"
|
||||
if [ -d "$directory" ]; then
|
||||
fail=0
|
||||
owners=$(ls -lL $directory | grep ".crt" | awk '{print $3, $4}')
|
||||
for p in $owners; do
|
||||
printf "%s" "$p" | grep "root" >/dev/null 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
fail=1
|
||||
file=$(get_service_file docker.service)
|
||||
if [ -f "$file" ]; then
|
||||
if [ "$(stat -c %u%g "$file")" -eq 00 ]; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
done
|
||||
if [ $fail -eq 1 ]; then
|
||||
warn "$check_3_7"
|
||||
warn " * Wrong ownership for $directory"
|
||||
else
|
||||
pass "$check_3_7"
|
||||
warn -s "$check"
|
||||
warn " * Wrong ownership for $file"
|
||||
logcheckresult "WARN" "Wrong ownership for $file"
|
||||
return
|
||||
fi
|
||||
else
|
||||
info "$check_3_7"
|
||||
info " * Directory not found"
|
||||
fi
|
||||
info -c "$check"
|
||||
info " * File not found"
|
||||
logcheckresult "INFO" "File not found"
|
||||
}
|
||||
|
||||
# 3.8
|
||||
check_3_8="3.8 - Verify that registry certificate file permissions are set to 444 or more restrictive"
|
||||
directory="/etc/docker/certs.d/"
|
||||
if [ -d "$directory" ]; then
|
||||
fail=0
|
||||
perms=$(ls -lL $directory | grep ".crt" | awk '{print $1}')
|
||||
for p in $perms; do
|
||||
if [ "$p" != "-r--r--r--." -a "$p" = "-r--------." ]; then
|
||||
fail=1
|
||||
check_3_2() {
|
||||
local id="3.2"
|
||||
local desc="Ensure that docker.service file permissions are appropriately set (Automated)"
|
||||
local remediation="Find out the file location: systemctl show -p FragmentPath docker.service. If the file does not exist, this recommendation is not applicable. If the file exists, run the command chmod 644 <path> to set the file permissions to 644."
|
||||
local remediationImpact="None."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
file=$(get_service_file docker.service)
|
||||
if [ -f "$file" ]; then
|
||||
if [ "$(stat -c %a "$file")" -le 644 ]; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
done
|
||||
if [ $fail -eq 1 ]; then
|
||||
warn "$check_3_8"
|
||||
warn " * Wrong permissions for $directory"
|
||||
else
|
||||
pass "$check_3_8"
|
||||
warn -s "$check"
|
||||
warn " * Wrong permissions for $file"
|
||||
logcheckresult "WARN" "Wrong permissions for $file"
|
||||
return
|
||||
fi
|
||||
else
|
||||
info "$check_3_8"
|
||||
info " * Directory not found"
|
||||
fi
|
||||
info -c "$check"
|
||||
info " * File not found"
|
||||
logcheckresult "INFO" "File not found"
|
||||
}
|
||||
|
||||
# 3.9
|
||||
check_3_9="3.9 - Verify that TLS CA certificate file ownership is set to root:root"
|
||||
tlscacert=$(get_docker_effective_command_line_args '--tlscacert' | sed -n 's/.*tlscacert=\([^s]\)/\1/p' | sed 's/--/ --/g' | cut -d " " -f 1)
|
||||
if [ -f "$tlscacert" ]; then
|
||||
if [ "$(stat -c %u%g "$tlscacert")" -eq 00 ]; then
|
||||
pass "$check_3_9"
|
||||
else
|
||||
warn "$check_3_9"
|
||||
check_3_3() {
|
||||
local id="3.3"
|
||||
local desc="Ensure that docker.socket file ownership is set to root:root (Automated)"
|
||||
local remediation="Find out the file location: systemctl show -p FragmentPath docker.socket. If the file does not exist, this recommendation is not applicable. If the file exists, run the command chown root:root <path> to set the ownership and group ownership for the file to root."
|
||||
local remediationImpact="None."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
file=$(get_service_file docker.socket)
|
||||
if [ -f "$file" ]; then
|
||||
if [ "$(stat -c %u%g "$file")" -eq 00 ]; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
warn " * Wrong ownership for $file"
|
||||
logcheckresult "WARN" "Wrong ownership for $file"
|
||||
return
|
||||
fi
|
||||
info -c "$check"
|
||||
info " * File not found"
|
||||
logcheckresult "INFO" "File not found"
|
||||
}
|
||||
|
||||
check_3_4() {
|
||||
local id="3.4"
|
||||
local desc="Ensure that docker.socket file permissions are set to 644 or more restrictive (Automated)"
|
||||
local remediation="Find out the file location: systemctl show -p FragmentPath docker.socket. If the file does not exist, this recommendation is not applicable. If the file does exist, you should run the command chmod 644 <path> to set the file permissions to 644."
|
||||
local remediationImpact="None."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
file=$(get_service_file docker.socket)
|
||||
if [ -f "$file" ]; then
|
||||
if [ "$(stat -c %a "$file")" -le 644 ]; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
warn " * Wrong permissions for $file"
|
||||
logcheckresult "WARN" "Wrong permissions for $file"
|
||||
return
|
||||
fi
|
||||
info -c "$check"
|
||||
info " * File not found"
|
||||
logcheckresult "INFO" "File not found"
|
||||
}
|
||||
|
||||
check_3_5() {
|
||||
local id="3.5"
|
||||
local desc="Ensure that the /etc/docker directory ownership is set to root:root (Automated)"
|
||||
local remediation="You should run the following command: chown root:root /etc/docker. This sets the ownership and group ownership for the directory to root."
|
||||
local remediationImpact="None."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
directory="/etc/docker"
|
||||
if [ -d "$directory" ]; then
|
||||
if [ "$(stat -c %u%g $directory)" -eq 00 ]; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
warn " * Wrong ownership for $directory"
|
||||
logcheckresult "WARN" "Wrong ownership for $directory"
|
||||
return
|
||||
fi
|
||||
info -c "$check"
|
||||
info " * Directory not found"
|
||||
logcheckresult "INFO" "Directory not found"
|
||||
}
|
||||
|
||||
check_3_6() {
|
||||
local id="3.6"
|
||||
local desc="Ensure that /etc/docker directory permissions are set to 755 or more restrictively (Automated)"
|
||||
local remediation="You should run the following command: chmod 755 /etc/docker. This sets the permissions for the directory to 755."
|
||||
local remediationImpact="None."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
directory="/etc/docker"
|
||||
if [ -d "$directory" ]; then
|
||||
if [ "$(stat -c %a $directory)" -le 755 ]; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
warn " * Wrong permissions for $directory"
|
||||
logcheckresult "WARN" "Wrong permissions for $directory"
|
||||
return
|
||||
fi
|
||||
info -c "$check"
|
||||
info " * Directory not found"
|
||||
logcheckresult "INFO" "Directory not found"
|
||||
}
|
||||
|
||||
check_3_7() {
|
||||
local id="3.7"
|
||||
local desc="Ensure that registry certificate file ownership is set to root:root (Automated)"
|
||||
local remediation="You should run the following command: chown root:root /etc/docker/certs.d/<registry-name>/*. This would set the individual ownership and group ownership for the registry certificate files to root."
|
||||
local remediationImpact="None."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
directory="/etc/docker/certs.d/"
|
||||
if [ -d "$directory" ]; then
|
||||
fail=0
|
||||
owners=$(find "$directory" -type f -name '*.crt')
|
||||
for p in $owners; do
|
||||
if [ "$(stat -c %u "$p")" -ne 0 ]; then
|
||||
fail=1
|
||||
fi
|
||||
done
|
||||
if [ $fail -eq 1 ]; then
|
||||
warn -s "$check"
|
||||
warn " * Wrong ownership for $directory"
|
||||
logcheckresult "WARN" "Wrong ownership for $directory"
|
||||
return
|
||||
fi
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
info -c "$check"
|
||||
info " * Directory not found"
|
||||
logcheckresult "INFO" "Directory not found"
|
||||
}
|
||||
|
||||
check_3_8() {
|
||||
local id="3.8"
|
||||
local desc="Ensure that registry certificate file permissions are set to 444 or more restrictively (Automated)"
|
||||
local remediation="You should run the following command: chmod 444 /etc/docker/certs.d/<registry-name>/*. This would set the permissions for the registry certificate files to 444."
|
||||
local remediationImpact="None."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
directory="/etc/docker/certs.d/"
|
||||
if [ -d "$directory" ]; then
|
||||
fail=0
|
||||
perms=$(find "$directory" -type f -name '*.crt')
|
||||
for p in $perms; do
|
||||
if [ "$(stat -c %a "$p")" -gt 444 ]; then
|
||||
fail=1
|
||||
fi
|
||||
done
|
||||
if [ $fail -eq 1 ]; then
|
||||
warn -s "$check"
|
||||
warn " * Wrong permissions for $directory"
|
||||
logcheckresult "WARN" "Wrong permissions for $directory"
|
||||
return
|
||||
fi
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
info -c "$check"
|
||||
info " * Directory not found"
|
||||
logcheckresult "INFO" "Directory not found"
|
||||
}
|
||||
|
||||
check_3_9() {
|
||||
local id="3.9"
|
||||
local desc="Ensure that TLS CA certificate file ownership is set to root:root (Automated)"
|
||||
local remediation="You should run the following command: chown root:root <path to TLS CA certificate file>. This sets the individual ownership and group ownership for the TLS CA certificate file to root."
|
||||
local remediationImpact="None."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
tlscacert=$(get_docker_effective_command_line_args '--tlscacert' | sed -n 's/.*tlscacert=\([^s]\)/\1/p' | sed 's/--/ --/g' | cut -d " " -f 1)
|
||||
if [ -n "$(get_docker_configuration_file_args 'tlscacert')" ]; then
|
||||
tlscacert=$(get_docker_configuration_file_args 'tlscacert')
|
||||
fi
|
||||
if [ -f "$tlscacert" ]; then
|
||||
if [ "$(stat -c %u%g "$tlscacert")" -eq 00 ]; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
warn " * Wrong ownership for $tlscacert"
|
||||
logcheckresult "WARN" "Wrong ownership for $tlscacert"
|
||||
return
|
||||
fi
|
||||
else
|
||||
info "$check_3_9"
|
||||
info -c "$check"
|
||||
info " * No TLS CA certificate found"
|
||||
fi
|
||||
logcheckresult "INFO" "No TLS CA certificate found"
|
||||
}
|
||||
|
||||
# 3.10
|
||||
check_3_10="3.10 - Verify that TLS CA certificate file permissions are set to 444 or more restrictive"
|
||||
tlscacert=$(get_docker_effective_command_line_args '--tlscacert' | sed -n 's/.*tlscacert=\([^s]\)/\1/p' | sed 's/--/ --/g' | cut -d " " -f 1)
|
||||
if [ -f "$tlscacert" ]; then
|
||||
perms=$(ls -ld "$tlscacert" | awk '{print $1}')
|
||||
if [ "$perms" = "-r--r--r--" ]; then
|
||||
pass "$check_3_10"
|
||||
else
|
||||
warn "$check_3_10"
|
||||
warn " * Wrong permissions for $tlscacert"
|
||||
fi
|
||||
else
|
||||
info "$check_3_10"
|
||||
info " * No TLS CA certificate found"
|
||||
fi
|
||||
check_3_10() {
|
||||
local id="3.10"
|
||||
local desc="Ensure that TLS CA certificate file permissions are set to 444 or more restrictively (Automated)"
|
||||
local remediation="You should run the following command: chmod 444 <path to TLS CA certificate file>. This sets the file permissions on the TLS CA file to 444."
|
||||
local remediationImpact="None."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
# 3.11
|
||||
check_3_11="3.11 - Verify that Docker server certificate file ownership is set to root:root"
|
||||
tlscert=$(get_docker_effective_command_line_args '--tlscert' | sed -n 's/.*tlscert=\([^s]\)/\1/p' | sed 's/--/ --/g' | cut -d " " -f 1)
|
||||
if [ -f "$tlscert" ]; then
|
||||
if [ "$(stat -c %u%g "$tlscert")" -eq 00 ]; then
|
||||
pass "$check_3_11"
|
||||
else
|
||||
warn "$check_3_11"
|
||||
warn " * Wrong ownership for $tlscert"
|
||||
tlscacert=$(get_docker_effective_command_line_args '--tlscacert' | sed -n 's/.*tlscacert=\([^s]\)/\1/p' | sed 's/--/ --/g' | cut -d " " -f 1)
|
||||
if [ -n "$(get_docker_configuration_file_args 'tlscacert')" ]; then
|
||||
tlscacert=$(get_docker_configuration_file_args 'tlscacert')
|
||||
fi
|
||||
else
|
||||
info "$check_3_11"
|
||||
info " * No TLS Server certificate found"
|
||||
fi
|
||||
if [ -f "$tlscacert" ]; then
|
||||
if [ "$(stat -c %a "$tlscacert")" -le 444 ]; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
warn " * Wrong permissions for $tlscacert"
|
||||
logcheckresult "WARN" "Wrong permissions for $tlscacert"
|
||||
return
|
||||
fi
|
||||
info -c "$check"
|
||||
info " * No TLS CA certificate found"
|
||||
logcheckresult "INFO" "No TLS CA certificate found"
|
||||
}
|
||||
|
||||
# 3.12
|
||||
check_3_12="3.12 - Verify that Docker server certificate file permissions are set to 444 or more restrictive"
|
||||
tlscert=$(get_docker_effective_command_line_args '--tlscert' | sed -n 's/.*tlscert=\([^s]\)/\1/p' | sed 's/--/ --/g' | cut -d " " -f 1)
|
||||
if [ -f "$tlscert" ]; then
|
||||
perms=$(ls -ld "$tlscert" | awk '{print $1}')
|
||||
if [ "$perms" = "-r--r--r--" ]; then
|
||||
pass "$check_3_12"
|
||||
else
|
||||
warn "$check_3_12"
|
||||
warn " * Wrong permissions for $tlscert"
|
||||
fi
|
||||
else
|
||||
info "$check_3_12"
|
||||
info " * No TLS Server certificate found"
|
||||
fi
|
||||
check_3_11() {
|
||||
local id="3.11"
|
||||
local desc="Ensure that Docker server certificate file ownership is set to root:root (Automated)"
|
||||
local remediation="You should run the following command: chown root:root <path to Docker server certificate file>. This sets the individual ownership and the group ownership for the Docker server certificate file to root."
|
||||
local remediationImpact="None."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
# 3.13
|
||||
check_3_13="3.13 - Verify that Docker server key file ownership is set to root:root"
|
||||
tlskey=$(get_docker_effective_command_line_args '--tlskey' | sed -n 's/.*tlskey=\([^s]\)/\1/p' | sed 's/--/ --/g' | cut -d " " -f 1)
|
||||
if [ -f "$tlskey" ]; then
|
||||
if [ "$(stat -c %u%g "$tlskey")" -eq 00 ]; then
|
||||
pass "$check_3_13"
|
||||
else
|
||||
warn "$check_3_13"
|
||||
warn " * Wrong ownership for $tlskey"
|
||||
tlscert=$(get_docker_effective_command_line_args '--tlscert' | sed -n 's/.*tlscert=\([^s]\)/\1/p' | sed 's/--/ --/g' | cut -d " " -f 1)
|
||||
if [ -n "$(get_docker_configuration_file_args 'tlscert')" ]; then
|
||||
tlscert=$(get_docker_configuration_file_args 'tlscert')
|
||||
fi
|
||||
else
|
||||
info "$check_3_13"
|
||||
info " * No TLS Key found"
|
||||
fi
|
||||
if [ -f "$tlscert" ]; then
|
||||
if [ "$(stat -c %u%g "$tlscert")" -eq 00 ]; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
warn " * Wrong ownership for $tlscert"
|
||||
logcheckresult "WARN" "Wrong ownership for $tlscert"
|
||||
return
|
||||
fi
|
||||
info -c "$check"
|
||||
info " * No TLS Server certificate found"
|
||||
logcheckresult "INFO" "No TLS Server certificate found"
|
||||
}
|
||||
|
||||
# 3.14
|
||||
check_3_14="3.14 - Verify that Docker server key file permissions are set to 400 or more restrictive"
|
||||
tlskey=$(get_docker_effective_command_line_args '--tlskey' | sed -n 's/.*tlskey=\([^s]\)/\1/p' | sed 's/--/ --/g' | cut -d " " -f 1)
|
||||
if [ -f "$tlskey" ]; then
|
||||
perms=$(ls -ld "$tlskey" | awk '{print $1}')
|
||||
if [ "$perms" = "-r--------" ]; then
|
||||
pass "$check_3_14"
|
||||
else
|
||||
warn "$check_3_14"
|
||||
warn " * Wrong permissions for $tlskey"
|
||||
fi
|
||||
else
|
||||
info "$check_3_14"
|
||||
info " * No TLS Key found"
|
||||
fi
|
||||
check_3_12() {
|
||||
local id="3.12"
|
||||
local desc="Ensure that the Docker server certificate file permissions are set to 444 or more restrictively (Automated)"
|
||||
local remediation="You should run the following command: chmod 444 <path to Docker server certificate file>. This sets the file permissions of the Docker server certificate file to 444."
|
||||
local remediationImpact="None."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
# 3.15
|
||||
check_3_15="3.15 - Verify that Docker socket file ownership is set to root:docker"
|
||||
file="/var/run/docker.sock"
|
||||
if [ -S "$file" ]; then
|
||||
if [ "$(stat -c %U:%G $file)" = 'root:docker' ]; then
|
||||
pass "$check_3_15"
|
||||
else
|
||||
warn "$check_3_15"
|
||||
warn " * Wrong ownership for $file"
|
||||
tlscert=$(get_docker_effective_command_line_args '--tlscert' | sed -n 's/.*tlscert=\([^s]\)/\1/p' | sed 's/--/ --/g' | cut -d " " -f 1)
|
||||
if [ -n "$(get_docker_configuration_file_args 'tlscert')" ]; then
|
||||
tlscert=$(get_docker_configuration_file_args 'tlscert')
|
||||
fi
|
||||
else
|
||||
info "$check_3_15"
|
||||
info " * File not found"
|
||||
fi
|
||||
if [ -f "$tlscert" ]; then
|
||||
if [ "$(stat -c %a "$tlscert")" -le 444 ]; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
warn " * Wrong permissions for $tlscert"
|
||||
logcheckresult "WARN" "Wrong permissions for $tlscert"
|
||||
return
|
||||
fi
|
||||
info -c "$check"
|
||||
info " * No TLS Server certificate found"
|
||||
logcheckresult "INFO" "No TLS Server certificate found"
|
||||
}
|
||||
|
||||
# 3.16
|
||||
check_3_16="3.16 - Verify that Docker socket file permissions are set to 660 or more restrictive"
|
||||
file="/var/run/docker.sock"
|
||||
if [ -S "$file" ]; then
|
||||
if [ "$(stat -c %a $file)" -eq 660 -o "$(stat -c %a $file)" -eq 600 ]; then
|
||||
pass "$check_3_16"
|
||||
else
|
||||
warn "$check_3_16"
|
||||
warn " * Wrong permissions for $file"
|
||||
fi
|
||||
else
|
||||
info "$check_3_16"
|
||||
info " * File not found"
|
||||
fi
|
||||
check_3_13() {
|
||||
local id="3.13"
|
||||
local desc="Ensure that the Docker server certificate key file ownership is set to root:root (Automated)"
|
||||
local remediation="You should run the following command: chown root:root <path to Docker server certificate key file>. This sets the individual ownership and group ownership for the Docker server certificate key file to root."
|
||||
local remediationImpact="None."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
# 3.17
|
||||
check_3_17="3.17 - Verify that daemon.json file ownership is set to root:root"
|
||||
file="/etc/docker/daemon.json"
|
||||
if [ -f "$file" ]; then
|
||||
if [ "$(stat -c %U:%G $file)" = 'root:root' ]; then
|
||||
pass "$check_3_17"
|
||||
else
|
||||
warn "$check_3_17"
|
||||
warn " * Wrong ownership for $file"
|
||||
tlskey=$(get_docker_effective_command_line_args '--tlskey' | sed -n 's/.*tlskey=\([^s]\)/\1/p' | sed 's/--/ --/g' | cut -d " " -f 1)
|
||||
if [ -n "$(get_docker_configuration_file_args 'tlskey')" ]; then
|
||||
tlskey=$(get_docker_configuration_file_args 'tlskey')
|
||||
fi
|
||||
else
|
||||
info "$check_3_17"
|
||||
info " * File not found"
|
||||
fi
|
||||
if [ -f "$tlskey" ]; then
|
||||
if [ "$(stat -c %u%g "$tlskey")" -eq 00 ]; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
warn " * Wrong ownership for $tlskey"
|
||||
logcheckresult "WARN" "Wrong ownership for $tlskey"
|
||||
return
|
||||
fi
|
||||
info -c "$check"
|
||||
info " * No TLS Key found"
|
||||
logcheckresult "INFO" "No TLS Key found"
|
||||
}
|
||||
|
||||
# 3.18
|
||||
check_3_18="3.18 - Verify that daemon.json file permissions are set to 644 or more restrictive"
|
||||
file="/etc/docker/daemon.json"
|
||||
if [ -f "$file" ]; then
|
||||
if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 600 ]; then
|
||||
pass "$check_3_18"
|
||||
else
|
||||
warn "$check_3_18"
|
||||
warn " * Wrong permissions for $file"
|
||||
fi
|
||||
else
|
||||
info "$check_3_18"
|
||||
info " * File not found"
|
||||
fi
|
||||
check_3_14() {
|
||||
local id="3.14"
|
||||
local desc="Ensure that the Docker server certificate key file permissions are set to 400 (Automated)"
|
||||
local remediation="You should run the following command: chmod 400 <path to Docker server certificate key file>. This sets the Docker server certificate key file permissions to 400."
|
||||
local remediationImpact="None."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
# 3.19
|
||||
check_3_19="3.19 - Verify that /etc/default/docker file ownership is set to root:root"
|
||||
file="/etc/default/docker"
|
||||
if [ -f "$file" ]; then
|
||||
if [ "$(stat -c %U:%G $file)" = 'root:root' ]; then
|
||||
pass "$check_3_19"
|
||||
else
|
||||
warn "$check_3_19"
|
||||
warn " * Wrong ownership for $file"
|
||||
tlskey=$(get_docker_effective_command_line_args '--tlskey' | sed -n 's/.*tlskey=\([^s]\)/\1/p' | sed 's/--/ --/g' | cut -d " " -f 1)
|
||||
if [ -n "$(get_docker_configuration_file_args 'tlskey')" ]; then
|
||||
tlskey=$(get_docker_configuration_file_args 'tlskey')
|
||||
fi
|
||||
else
|
||||
info "$check_3_19"
|
||||
info " * File not found"
|
||||
fi
|
||||
if [ -f "$tlskey" ]; then
|
||||
if [ "$(stat -c %a "$tlskey")" -eq 400 ]; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
warn " * Wrong permissions for $tlskey"
|
||||
logcheckresult "WARN" "Wrong permissions for $tlskey"
|
||||
return
|
||||
fi
|
||||
info -c "$check"
|
||||
info " * No TLS Key found"
|
||||
logcheckresult "INFO" "No TLS Key found"
|
||||
}
|
||||
|
||||
# 3.20
|
||||
check_3_20="3.20 - Verify that /etc/default/docker file permissions are set to 644 or more restrictive"
|
||||
file="/etc/default/docker"
|
||||
if [ -f "$file" ]; then
|
||||
if [ "$(stat -c %a $file)" -eq 644 -o "$(stat -c %a $file)" -eq 600 ]; then
|
||||
pass "$check_3_20"
|
||||
else
|
||||
warn "$check_3_20"
|
||||
warn " * Wrong permissions for $file"
|
||||
check_3_15() {
|
||||
local id="3.15"
|
||||
local desc="Ensure that the Docker socket file ownership is set to root:docker (Automated)"
|
||||
local remediation="You should run the following command: chown root:docker /var/run/docker.sock. This sets the ownership to root and group ownership to docker for the default Docker socket file."
|
||||
local remediationImpact="None."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
file="/var/run/docker.sock"
|
||||
if [ -S "$file" ]; then
|
||||
if [ "$(stat -c %U:%G $file)" = 'root:docker' ]; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
warn " * Wrong ownership for $file"
|
||||
logcheckresult "WARN" "Wrong ownership for $file"
|
||||
return
|
||||
fi
|
||||
else
|
||||
info "$check_3_20"
|
||||
info " * File not found"
|
||||
fi
|
||||
info -c "$check"
|
||||
info " * File not found"
|
||||
logcheckresult "INFO" "File not found"
|
||||
}
|
||||
|
||||
check_3_16() {
|
||||
local id="3.16"
|
||||
local desc="Ensure that the Docker socket file permissions are set to 660 or more restrictively (Automated)"
|
||||
local remediation="You should run the following command: chmod 660 /var/run/docker.sock. This sets the file permissions of the Docker socket file to 660."
|
||||
local remediationImpact="None."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
file="/var/run/docker.sock"
|
||||
if [ -S "$file" ]; then
|
||||
if [ "$(stat -c %a $file)" -le 660 ]; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
warn " * Wrong permissions for $file"
|
||||
logcheckresult "WARN" "Wrong permissions for $file"
|
||||
return
|
||||
fi
|
||||
info -c "$check"
|
||||
info " * File not found"
|
||||
logcheckresult "INFO" "File not found"
|
||||
}
|
||||
|
||||
check_3_17() {
|
||||
local id="3.17"
|
||||
local desc="Ensure that the daemon.json file ownership is set to root:root (Automated)"
|
||||
local remediation="You should run the following command: chown root:root /etc/docker/daemon.json. This sets the ownership and group ownership for the file to root."
|
||||
local remediationImpact="None."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
file="/etc/docker/daemon.json"
|
||||
if [ -f "$file" ]; then
|
||||
if [ "$(stat -c %U:%G $file)" = 'root:root' ]; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
warn " * Wrong ownership for $file"
|
||||
logcheckresult "WARN" "Wrong ownership for $file"
|
||||
return
|
||||
fi
|
||||
info -c "$check"
|
||||
info " * File not found"
|
||||
logcheckresult "INFO" "File not found"
|
||||
}
|
||||
|
||||
check_3_18() {
|
||||
local id="3.18"
|
||||
local desc="Ensure that daemon.json file permissions are set to 644 or more restrictive (Automated)"
|
||||
local remediation="You should run the following command: chmod 644 /etc/docker/daemon.json. This sets the file permissions for this file to 644."
|
||||
local remediationImpact="None."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
file="/etc/docker/daemon.json"
|
||||
if [ -f "$file" ]; then
|
||||
if [ "$(stat -c %a $file)" -le 644 ]; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
warn " * Wrong permissions for $file"
|
||||
logcheckresult "WARN" "Wrong permissions for $file"
|
||||
return
|
||||
fi
|
||||
info -c "$check"
|
||||
info " * File not found"
|
||||
logcheckresult "INFO" "File not found"
|
||||
}
|
||||
|
||||
check_3_19() {
|
||||
local id="3.19"
|
||||
local desc="Ensure that the /etc/default/docker file ownership is set to root:root (Automated)"
|
||||
local remediation="You should run the following command: chown root:root /etc/default/docker. This sets the ownership and group ownership of the file to root."
|
||||
local remediationImpact="None."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
file="/etc/default/docker"
|
||||
if [ -f "$file" ]; then
|
||||
if [ "$(stat -c %U:%G $file)" = 'root:root' ]; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
warn " * Wrong ownership for $file"
|
||||
logcheckresult "WARN" "Wrong ownership for $file"
|
||||
return
|
||||
fi
|
||||
info -c "$check"
|
||||
info " * File not found"
|
||||
logcheckresult "INFO" "File not found"
|
||||
}
|
||||
|
||||
check_3_20() {
|
||||
local id="3.20"
|
||||
local desc="Ensure that the /etc/default/docker file permissions are set to 644 or more restrictively (Automated)"
|
||||
local remediation="You should run the following command: chmod 644 /etc/default/docker. This sets the file permissions for this file to 644."
|
||||
local remediationImpact="None."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
file="/etc/default/docker"
|
||||
if [ -f "$file" ]; then
|
||||
if [ "$(stat -c %a $file)" -le 644 ]; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
warn " * Wrong permissions for $file"
|
||||
logcheckresult "WARN" "Wrong permissions for $file"
|
||||
return
|
||||
fi
|
||||
info -c "$check"
|
||||
info " * File not found"
|
||||
logcheckresult "INFO" "File not found"
|
||||
}
|
||||
|
||||
check_3_21() {
|
||||
local id="3.21"
|
||||
local desc="Ensure that the /etc/sysconfig/docker file permissions are set to 644 or more restrictively (Automated)"
|
||||
local remediation="You should run the following command: chmod 644 /etc/sysconfig/docker. This sets the file permissions for this file to 644."
|
||||
local remediationImpact="None."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
file="/etc/sysconfig/docker"
|
||||
if [ -f "$file" ]; then
|
||||
if [ "$(stat -c %a $file)" -le 644 ]; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
warn " * Wrong permissions for $file"
|
||||
logcheckresult "WARN" "Wrong permissions for $file"
|
||||
return
|
||||
fi
|
||||
info -c "$check"
|
||||
info " * File not found"
|
||||
logcheckresult "INFO" "File not found"
|
||||
}
|
||||
|
||||
check_3_22() {
|
||||
local id="3.22"
|
||||
local desc="Ensure that the /etc/sysconfig/docker file ownership is set to root:root (Automated)"
|
||||
local remediation="You should run the following command: chown root:root /etc/sysconfig/docker. This sets the ownership and group ownership for the file to root."
|
||||
local remediationImpact="None."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
file="/etc/sysconfig/docker"
|
||||
if [ -f "$file" ]; then
|
||||
if [ "$(stat -c %U:%G $file)" = 'root:root' ]; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
warn " * Wrong ownership for $file"
|
||||
logcheckresult "WARN" "Wrong ownership for $file"
|
||||
return
|
||||
fi
|
||||
info -c "$check"
|
||||
info " * File not found"
|
||||
logcheckresult "INFO" "File not found"
|
||||
}
|
||||
|
||||
check_3_23() {
|
||||
local id="3.23"
|
||||
local desc="Ensure that the Containerd socket file ownership is set to root:root (Automated)"
|
||||
local remediation="You should run the following command: chown root:root /run/containerd/containerd.sock. This sets the ownership and group ownership for the file to root."
|
||||
local remediationImpact="None."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
file="/run/containerd/containerd.sock"
|
||||
if [ -S "$file" ]; then
|
||||
if [ "$(stat -c %U:%G $file)" = 'root:root' ]; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
warn " * Wrong ownership for $file"
|
||||
logcheckresult "WARN" "Wrong ownership for $file"
|
||||
return
|
||||
fi
|
||||
info -c "$check"
|
||||
info " * File not found"
|
||||
logcheckresult "INFO" "File not found"
|
||||
}
|
||||
|
||||
check_3_24() {
|
||||
local id="3.24"
|
||||
local desc="Ensure that the Containerd socket file permissions are set to 660 or more restrictively (Automated)"
|
||||
local remediation="You should run the following command: chmod 660 /run/containerd/containerd.sock. This sets the file permissions for this file to 660."
|
||||
local remediationImpact="None."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
file="/run/containerd/containerd.sock"
|
||||
if [ -S "$file" ]; then
|
||||
if [ "$(stat -c %a $file)" -le 660 ]; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
warn " * Wrong permissions for $file"
|
||||
logcheckresult "WARN" "Wrong permissions for $file"
|
||||
return
|
||||
fi
|
||||
info -c "$check"
|
||||
info " * File not found"
|
||||
logcheckresult "INFO" "File not found"
|
||||
}
|
||||
|
||||
check_3_end() {
|
||||
endsectionjson
|
||||
}
|
||||
|
|
|
@ -1,133 +1,260 @@
|
|||
#!/bin/sh
|
||||
#!/bin/bash
|
||||
|
||||
logit "\n"
|
||||
info "4 - Container Images and Build Files"
|
||||
check_4() {
|
||||
logit ""
|
||||
local id="4"
|
||||
local desc="Container Images and Build File"
|
||||
checkHeader="$id - $desc"
|
||||
info "$checkHeader"
|
||||
startsectionjson "$id" "$desc"
|
||||
}
|
||||
|
||||
# 4.1
|
||||
check_4_1="4.1 - Create a user for the container"
|
||||
check_4_1() {
|
||||
local id="4.1"
|
||||
local desc="Ensure that a user for the container has been created (Automated)"
|
||||
local remediation="You should ensure that the Dockerfile for each container image contains the information: USER <username or ID>. If there is no specific user created in the container base image, then make use of the useradd command to add a specific user before the USER instruction in the Dockerfile."
|
||||
local remediationImpact="Running as a non-root user can present challenges where you wish to bind mount volumes from the underlying host. In this case, care should be taken to ensure that the user running the contained process can read and write to the bound directory, according to their requirements."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
# If container_users is empty, there are no running containers
|
||||
if [ -z "$containers" ]; then
|
||||
info "$check_4_1"
|
||||
info " * No containers running"
|
||||
else
|
||||
# If container_users is empty, there are no running containers
|
||||
if [ -z "$containers" ]; then
|
||||
info -c "$check"
|
||||
info " * No containers running"
|
||||
logcheckresult "INFO" "No containers running"
|
||||
return
|
||||
fi
|
||||
# We have some containers running, set failure flag to 0. Check for Users.
|
||||
fail=0
|
||||
# Make the loop separator be a new-line in POSIX compliant fashion
|
||||
set -f; IFS=$'
|
||||
'
|
||||
'
|
||||
root_containers=""
|
||||
for c in $containers; do
|
||||
user=$(docker inspect --format 'User={{.Config.User}}' "$c")
|
||||
|
||||
if [ "$user" = "User=" -o "$user" = "User=[]" -o "$user" = "User=<no value>" ]; then
|
||||
if [ "$user" = "User=0" ] || [ "$user" = "User=root" ] || [ "$user" = "User=" ] || [ "$user" = "User=[]" ] || [ "$user" = "User=<no value>" ]; then
|
||||
# If it's the first container, fail the test
|
||||
if [ $fail -eq 0 ]; then
|
||||
warn "$check_4_1"
|
||||
warn -s "$check"
|
||||
warn " * Running as root: $c"
|
||||
root_containers="$root_containers $c"
|
||||
fail=1
|
||||
else
|
||||
warn " * Running as root: $c"
|
||||
continue
|
||||
fi
|
||||
warn " * Running as root: $c"
|
||||
root_containers="$root_containers $c"
|
||||
fi
|
||||
done
|
||||
# We went through all the containers and found none running as root
|
||||
if [ $fail -eq 0 ]; then
|
||||
pass "$check_4_1"
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
fi
|
||||
# Make the loop separator go back to space
|
||||
set +f; unset IFS
|
||||
logcheckresult "WARN" "running as root" "$root_containers"
|
||||
# Make the loop separator go back to space
|
||||
set +f; unset IFS
|
||||
}
|
||||
|
||||
images=$(docker images -q)
|
||||
check_4_2() {
|
||||
local id="4.2"
|
||||
local desc="Ensure that containers use only trusted base images (Manual)"
|
||||
local remediation="Configure and use Docker Content trust. View the history of each Docker image to evaluate its risk, dependent on the sensitivity of the application you wish to deploy using it. Scan Docker images for vulnerabilities at regular intervals."
|
||||
local remediationImpact="None."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
# 4.2
|
||||
check_4_2="4.2 - Use trusted base images for containers"
|
||||
info "$check_4_2"
|
||||
note -c "$check"
|
||||
logcheckresult "NOTE"
|
||||
}
|
||||
|
||||
# 4.3
|
||||
check_4_3="4.3 - Do not install unnecessary packages in the container"
|
||||
info "$check_4_3"
|
||||
check_4_3() {
|
||||
local id="4.3"
|
||||
local desc="Ensure that unnecessary packages are not installed in the container (Manual)"
|
||||
local remediation="You should not install anything within the container that is not required. You should consider using a minimal base image if you can. Some of the options available include BusyBox and Alpine. Not only can this trim your image size considerably, but there would also be fewer pieces of software which could contain vectors for attack."
|
||||
local remediationImpact="None."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
# 4.4
|
||||
check_4_4="4.4 - Scan and rebuild the images to include security patches"
|
||||
info "$check_4_4"
|
||||
note -c "$check"
|
||||
logcheckresult "NOTE"
|
||||
}
|
||||
|
||||
# 4.5
|
||||
check_4_5="4.5 - Enable Content trust for Docker"
|
||||
if [ "x$DOCKER_CONTENT_TRUST" = "x1" ]; then
|
||||
pass "$check_4_5"
|
||||
else
|
||||
warn "$check_4_5"
|
||||
fi
|
||||
check_4_4() {
|
||||
local id="4.4"
|
||||
local desc="Ensure images are scanned and rebuilt to include security patches (Manual)"
|
||||
local remediation="Images should be re-built ensuring that the latest version of the base images are used, to keep the operating system patch level at an appropriate level. Once the images have been re-built, containers should be re-started making use of the updated images."
|
||||
local remediationImpact="None."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
# 4.6
|
||||
check_4_6="4.6 - Add HEALTHCHECK instruction to the container image"
|
||||
fail=0
|
||||
for img in $images; do
|
||||
docker inspect --format='{{.Config.Healthcheck}}' "$img" 2>/dev/null | grep -e "<nil>" >/dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
if [ $fail -eq 0 ]; then
|
||||
fail=1
|
||||
warn "$check_4_6"
|
||||
fi
|
||||
imgName=$(docker inspect --format='{{.RepoTags}}' "$img" 2>/dev/null)
|
||||
if ! [ "$imgName" = '[]' ]; then
|
||||
warn " * No Healthcheck found: $imgName"
|
||||
fi
|
||||
note -c "$check"
|
||||
logcheckresult "NOTE"
|
||||
}
|
||||
|
||||
check_4_5() {
|
||||
local id="4.5"
|
||||
local desc="Ensure Content trust for Docker is Enabled (Automated)"
|
||||
local remediation="Add DOCKER_CONTENT_TRUST variable to the /etc/environment file using command echo DOCKER_CONTENT_TRUST=1 | sudo tee -a /etc/environment."
|
||||
local remediationImpact="This prevents users from working with tagged images unless they contain a signature."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
if [ "$DOCKER_CONTENT_TRUST" = "1" ]; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
done
|
||||
if [ $fail -eq 0 ]; then
|
||||
pass "$check_4_6"
|
||||
fi
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
}
|
||||
|
||||
# 4.7
|
||||
check_4_7="4.7 - Do not use update instructions alone in the Dockerfile"
|
||||
fail=0
|
||||
for img in $images; do
|
||||
docker history "$img" 2>/dev/null | grep -e "update" >/dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
if [ $fail -eq 0 ]; then
|
||||
fail=1
|
||||
info "$check_4_7"
|
||||
fi
|
||||
imgName=$(docker inspect --format='{{.RepoTags}}' "$img" 2>/dev/null)
|
||||
if ! [ "$imgName" = '[]' ]; then
|
||||
info " * Update instruction found: $imgName"
|
||||
check_4_6() {
|
||||
local id="4.6"
|
||||
local desc="Ensure that HEALTHCHECK instructions have been added to container images (Automated)"
|
||||
local remediation="You should follow the Docker documentation and rebuild your container images to include the HEALTHCHECK instruction."
|
||||
local remediationImpact="None."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
fail=0
|
||||
no_health_images=""
|
||||
for img in $images; do
|
||||
if docker inspect --format='{{.Config.Healthcheck}}' "$img" 2>/dev/null | grep -e "<nil>" >/dev/null 2>&1; then
|
||||
if [ $fail -eq 0 ]; then
|
||||
fail=1
|
||||
warn -s "$check"
|
||||
fi
|
||||
imgName=$(docker inspect --format='{{.RepoTags}}' "$img" 2>/dev/null)
|
||||
if ! [ "$imgName" = '[]' ]; then
|
||||
warn " * No Healthcheck found: $imgName"
|
||||
no_health_images="$no_health_images $imgName"
|
||||
else
|
||||
warn " * No Healthcheck found: $img"
|
||||
no_health_images="$no_health_images $img"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
if [ $fail -eq 0 ]; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
done
|
||||
if [ $fail -eq 0 ]; then
|
||||
pass "$check_4_7"
|
||||
fi
|
||||
logcheckresult "WARN" "Images w/o HEALTHCHECK" "$no_health_images"
|
||||
}
|
||||
|
||||
# 4.8
|
||||
check_4_8="4.8 - Remove setuid and setgid permissions in the images"
|
||||
info "$check_4_8"
|
||||
check_4_7() {
|
||||
local id="4.7"
|
||||
local desc="Ensure update instructions are not used alone in the Dockerfile (Manual)"
|
||||
local remediation="You should use update instructions together with install instructions and version pinning for packages while installing them. This prevent caching and force the extraction of the required versions. Alternatively, you could use the --no-cache flag during the docker build process to avoid using cached layers."
|
||||
local remediationImpact="None."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
# 4.9
|
||||
check_4_9="4.9 - Use COPY instead of ADD in Dockerfile"
|
||||
fail=0
|
||||
for img in $images; do
|
||||
docker history "$img" 2> /dev/null | grep 'ADD' >/dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
if [ $fail -eq 0 ]; then
|
||||
fail=1
|
||||
info "$check_4_9"
|
||||
fi
|
||||
imgName=$(docker inspect --format='{{.RepoTags}}' "$img" 2>/dev/null)
|
||||
if ! [ "$imgName" = '[]' ]; then
|
||||
info " * ADD in image history: $imgName"
|
||||
fail=0
|
||||
update_images=""
|
||||
for img in $images; do
|
||||
if docker history "$img" 2>/dev/null | grep -e "update" >/dev/null 2>&1; then
|
||||
if [ $fail -eq 0 ]; then
|
||||
fail=1
|
||||
info -c "$check"
|
||||
fi
|
||||
imgName=$(docker inspect --format='{{.RepoTags}}' "$img" 2>/dev/null)
|
||||
if ! [ "$imgName" = '[]' ]; then
|
||||
info " * Update instruction found: $imgName"
|
||||
update_images="$update_images $imgName"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
if [ $fail -eq 0 ]; then
|
||||
pass -c "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
done
|
||||
if [ $fail -eq 0 ]; then
|
||||
pass "$check_4_9"
|
||||
fi
|
||||
logcheckresult "INFO" "Update instructions found" "$update_images"
|
||||
}
|
||||
|
||||
# 4.10
|
||||
check_4_10="4.10 - Do not store secrets in Dockerfiles"
|
||||
info "$check_4_10"
|
||||
check_4_8() {
|
||||
local id="4.8"
|
||||
local desc="Ensure setuid and setgid permissions are removed (Manual)"
|
||||
local remediation="You should allow setuid and setgid permissions only on executables which require them. You could remove these permissions at build time by adding the following command in your Dockerfile, preferably towards the end of the Dockerfile: RUN find / -perm /6000 -type f -exec chmod a-s {} ; || true"
|
||||
local remediationImpact="The above command would break all executables that depend on setuid or setgid permissions including legitimate ones. You should therefore be careful to modify the command to suit your requirements so that it does not reduce the permissions of legitimate programs excessively. Because of this, you should exercise a degree of caution and examine all processes carefully before making this type of modification in order to avoid outages."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
# 4.11
|
||||
check_4_11="4.11 - Install verified packages only"
|
||||
info "$check_4_11"
|
||||
note -c "$check"
|
||||
logcheckresult "NOTE"
|
||||
}
|
||||
|
||||
check_4_9() {
|
||||
local id="4.9"
|
||||
local desc="Ensure that COPY is used instead of ADD in Dockerfiles (Manual)"
|
||||
local remediation="You should use COPY rather than ADD instructions in Dockerfiles."
|
||||
local remediationImpact="Care needs to be taken in implementing this control if the application requires functionality that is part of the ADD instruction, for example, if you need to retrieve files from remote URLS."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
fail=0
|
||||
add_images=""
|
||||
for img in $images; do
|
||||
if docker history --format "{{ .CreatedBy }}" --no-trunc "$img" | \
|
||||
sed '$d' | grep -q 'ADD'; then
|
||||
if [ $fail -eq 0 ]; then
|
||||
fail=1
|
||||
info -c "$check"
|
||||
fi
|
||||
imgName=$(docker inspect --format='{{.RepoTags}}' "$img" 2>/dev/null)
|
||||
if ! [ "$imgName" = '[]' ]; then
|
||||
info " * ADD in image history: $imgName"
|
||||
add_images="$add_images $imgName"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
if [ $fail -eq 0 ]; then
|
||||
pass -c "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
logcheckresult "INFO" "Images using ADD" "$add_images"
|
||||
}
|
||||
|
||||
check_4_10() {
|
||||
local id="4.10"
|
||||
local desc="Ensure secrets are not stored in Dockerfiles (Manual)"
|
||||
local remediation="Do not store any kind of secrets within Dockerfiles. Where secrets are required during the build process, make use of a secrets management tool, such as the buildkit builder included with Docker."
|
||||
local remediationImpact="A proper secrets management process will be required for Docker image building."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
note -c "$check"
|
||||
logcheckresult "NOTE"
|
||||
}
|
||||
|
||||
check_4_11() {
|
||||
local id="4.11"
|
||||
local desc="Ensure only verified packages are installed (Manual)"
|
||||
local remediation="You should use a secure package distribution mechanism of your choice to ensure the authenticity of software packages."
|
||||
local remediationImpact="None."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
note -c "$check"
|
||||
logcheckresult "NOTE"
|
||||
}
|
||||
|
||||
check_4_12() {
|
||||
local id="4.12"
|
||||
local desc="Ensure all signed artifacts are validated (Manual)"
|
||||
local remediation="Validate artifacts signatures before uploading to the package registry."
|
||||
local remediationImpact="None."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
note -c "$check"
|
||||
logcheckresult "NOTE"
|
||||
}
|
||||
|
||||
check_4_end() {
|
||||
endsectionjson
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,47 +1,60 @@
|
|||
#!/bin/sh
|
||||
#!/bin/bash
|
||||
|
||||
logit "\n"
|
||||
info "6 - Docker Security Operations"
|
||||
check_6() {
|
||||
logit ""
|
||||
local id="6"
|
||||
local desc="Docker Security Operations"
|
||||
checkHeader="$id - $desc"
|
||||
info "$checkHeader"
|
||||
startsectionjson "$id" "$desc"
|
||||
}
|
||||
|
||||
# 6.1
|
||||
check_6_1="6.1 - Perform regular security audits of your host system and containers"
|
||||
info "$check_6_1"
|
||||
check_6_1() {
|
||||
local id="6.1"
|
||||
local desc="Ensure that image sprawl is avoided (Manual)"
|
||||
local remediation="You should keep only the images that you actually need and establish a workflow to remove old or stale images from the host. Additionally, you should use features such as pull-by-digest to get specific images from the registry."
|
||||
local remediationImpact="docker system prune -a removes all exited containers as well as all images and volumes that are not referenced by running containers, including for UCP and DTR."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
# 6.2
|
||||
check_6_2="6.2 - Monitor Docker containers usage, performance and metering"
|
||||
info "$check_6_2"
|
||||
images=$(docker images -q | sort -u | wc -l | awk '{print $1}')
|
||||
active_images=0
|
||||
|
||||
# 6.3
|
||||
check_6_3="6.3 - Backup container data"
|
||||
info "$check_6_3"
|
||||
for c in $(docker inspect --format "{{.Image}}" $(docker ps -qa) 2>/dev/null); do
|
||||
if docker images --no-trunc -a | grep "$c" > /dev/null ; then
|
||||
active_images=$(( active_images += 1 ))
|
||||
fi
|
||||
done
|
||||
|
||||
# 6.4
|
||||
check_6_4="6.4 - Avoid image sprawl"
|
||||
images=$(docker images -q | sort -u | wc -l | awk '{print $1}')
|
||||
active_images=0
|
||||
|
||||
for c in $(docker inspect -f "{{.Image}}" $(docker ps -qa)); do
|
||||
if docker images --no-trunc -a | grep "$c" > /dev/null ; then
|
||||
active_images=$(( active_images += 1 ))
|
||||
fi
|
||||
done
|
||||
|
||||
info "$check_6_4"
|
||||
info -c "$check"
|
||||
info " * There are currently: $images images"
|
||||
|
||||
if [ "$active_images" -lt "$((images / 2))" ]; then
|
||||
info " * Only $active_images out of $images are in use"
|
||||
fi
|
||||
if [ "$active_images" -lt "$((images / 2))" ]; then
|
||||
info " * Only $active_images out of $images are in use"
|
||||
fi
|
||||
logcheckresult "INFO" "$active_images active/$images in use"
|
||||
}
|
||||
|
||||
# 6.5
|
||||
check_6_5="6.5 - Avoid container sprawl"
|
||||
total_containers=$(docker info 2>/dev/null | grep "Containers" | awk '{print $2}')
|
||||
running_containers=$(docker ps -q | wc -l | awk '{print $1}')
|
||||
diff="$((total_containers - running_containers))"
|
||||
if [ "$diff" -gt 25 ]; then
|
||||
info "$check_6_5"
|
||||
info " * There are currently a total of $total_containers containers, with only $running_containers of them currently running"
|
||||
else
|
||||
info "$check_6_5"
|
||||
info " * There are currently a total of $total_containers containers, with $running_containers of them currently running"
|
||||
fi
|
||||
check_6_2() {
|
||||
local id="6.2"
|
||||
local desc="Ensure that container sprawl is avoided (Manual)"
|
||||
local remediation="You should periodically check your container inventory on each host and clean up containers which are not in active use with the command: docker container prune"
|
||||
local remediationImpact="You should retain containers that are actively in use, and delete ones which are no longer needed."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
total_containers=$(docker info 2>/dev/null | grep "Containers" | awk '{print $2}')
|
||||
running_containers=$(docker ps -q | wc -l | awk '{print $1}')
|
||||
diff="$((total_containers - running_containers))"
|
||||
info -c "$check"
|
||||
if [ "$diff" -gt 25 ]; then
|
||||
info " * There are currently a total of $total_containers containers, with only $running_containers of them currently running"
|
||||
else
|
||||
info " * There are currently a total of $total_containers containers, with $running_containers of them currently running"
|
||||
fi
|
||||
logcheckresult "INFO" "$total_containers total/$running_containers running"
|
||||
}
|
||||
|
||||
check_6_end() {
|
||||
endsectionjson
|
||||
}
|
||||
|
|
208
tests/7_docker_swarm_configuration.sh
Normal file
208
tests/7_docker_swarm_configuration.sh
Normal file
|
@ -0,0 +1,208 @@
|
|||
#!/bin/bash
|
||||
|
||||
check_7() {
|
||||
logit ""
|
||||
local id="7"
|
||||
local desc="Docker Swarm Configuration"
|
||||
checkHeader="$id - $desc"
|
||||
info "$checkHeader"
|
||||
startsectionjson "$id" "$desc"
|
||||
}
|
||||
|
||||
check_7_1() {
|
||||
local id="7.1"
|
||||
local desc="Ensure that the minimum number of manager nodes have been created in a swarm (Automated)"
|
||||
local remediation="If an excessive number of managers is configured, the excess nodes can be demoted to workers using command: docker node demote <manager node ID to be demoted>"
|
||||
local remediationImpact="None."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
if docker info 2>/dev/null | grep -e "Swarm:*\sactive\s*" >/dev/null 2>&1; then
|
||||
managernodes=$(docker node ls | grep -c "Leader")
|
||||
if [ "$managernodes" -eq 1 ]; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
return
|
||||
fi
|
||||
pass -s "$check (Swarm mode not enabled)"
|
||||
logcheckresult "PASS"
|
||||
}
|
||||
|
||||
check_7_2() {
|
||||
local id="7.2"
|
||||
local desc="Ensure that swarm services are bound to a specific host interface (Automated)"
|
||||
local remediation="Resolving this issues requires re-initialization of the swarm, specifying a specific interface for the --listen-addr parameter."
|
||||
local remediationImpact="None."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
if docker info 2>/dev/null | grep -e "Swarm:*\sactive\s*" >/dev/null 2>&1; then
|
||||
$netbin -lnt | grep -e '\[::]:2377 ' -e ':::2377' -e '*:2377 ' -e ' 0\.0\.0\.0:2377 ' >/dev/null 2>&1
|
||||
if [ $? -eq 1 ]; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
return
|
||||
fi
|
||||
pass -s "$check (Swarm mode not enabled)"
|
||||
logcheckresult "PASS"
|
||||
}
|
||||
|
||||
check_7_3() {
|
||||
local id="7.3"
|
||||
local desc="Ensure that all Docker swarm overlay networks are encrypted (Automated)"
|
||||
local remediation="You should create overlay networks the with --opt encrypted flag."
|
||||
local remediationImpact="None."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
fail=0
|
||||
unencrypted_networks=""
|
||||
for encnet in $(docker network ls --filter driver=overlay --quiet); do
|
||||
if docker network inspect --format '{{.Name}} {{ .Options }}' "$encnet" | \
|
||||
grep -v 'encrypted:' 2>/dev/null 1>&2; then
|
||||
# If it's the first container, fail the test
|
||||
if [ $fail -eq 0 ]; then
|
||||
warn -s "$check"
|
||||
fail=1
|
||||
fi
|
||||
warn " * Unencrypted overlay network: $(docker network inspect --format '{{ .Name }} ({{ .Scope }})' "$encnet")"
|
||||
unencrypted_networks="$unencrypted_networks $(docker network inspect --format '{{ .Name }} ({{ .Scope }})' "$encnet")"
|
||||
fi
|
||||
done
|
||||
# We went through all the networks and found none that are unencrypted
|
||||
if [ $fail -eq 0 ]; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
logcheckresult "WARN" "Unencrypted overlay networks:" "$unencrypted_networks"
|
||||
}
|
||||
|
||||
check_7_4() {
|
||||
local id="7.4"
|
||||
local desc="Ensure that Docker's secret management commands are used for managing secrets in a swarm cluster (Manual)"
|
||||
local remediation="You should follow the docker secret documentation and use it to manage secrets effectively."
|
||||
local remediationImpact="None."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
if docker info 2>/dev/null | grep -e "Swarm:\s*active\s*" >/dev/null 2>&1; then
|
||||
if [ "$(docker secret ls -q | wc -l)" -ge 1 ]; then
|
||||
pass -c "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
info -c "$check"
|
||||
logcheckresult "INFO"
|
||||
return
|
||||
fi
|
||||
pass -c "$check (Swarm mode not enabled)"
|
||||
logcheckresult "PASS"
|
||||
}
|
||||
|
||||
check_7_5() {
|
||||
local id="7.5"
|
||||
local desc="Ensure that swarm manager is run in auto-lock mode (Automated)"
|
||||
local remediation="If you are initializing a swarm, use the command: docker swarm init --autolock. If you want to set --autolock on an existing swarm manager node, use the command: docker swarm update --autolock."
|
||||
local remediationImpact="A swarm in auto-lock mode will not recover from a restart without manual intervention from an administrator to enter the unlock key. This may not always be desirable, and should be reviewed at a policy level."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
if docker info 2>/dev/null | grep -e "Swarm:\s*active\s*" >/dev/null 2>&1; then
|
||||
if ! docker swarm unlock-key 2>/dev/null | grep 'SWMKEY' 2>/dev/null 1>&2; then
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
return
|
||||
fi
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
pass -s "$check (Swarm mode not enabled)"
|
||||
logcheckresult "PASS"
|
||||
}
|
||||
|
||||
check_7_6() {
|
||||
local id="7.6"
|
||||
local desc="Ensure that the swarm manager auto-lock key is rotated periodically (Manual)"
|
||||
local remediation="You should run the command docker swarm unlock-key --rotate to rotate the keys. To facilitate auditing of this recommendation, you should maintain key rotation records and ensure that you establish a pre-defined frequency for key rotation."
|
||||
local remediationImpact="None."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
if docker info 2>/dev/null | grep -e "Swarm:\s*active\s*" >/dev/null 2>&1; then
|
||||
note -c "$check"
|
||||
logcheckresult "NOTE"
|
||||
return
|
||||
fi
|
||||
pass -c "$check (Swarm mode not enabled)"
|
||||
logcheckresult "PASS"
|
||||
}
|
||||
|
||||
check_7_7() {
|
||||
local id="7.7"
|
||||
local desc="Ensure that node certificates are rotated as appropriate (Manual)"
|
||||
local remediation="You should run the command docker swarm update --cert-expiry 48h to set the desired expiry time on the node certificate."
|
||||
local remediationImpact="None."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
if docker info 2>/dev/null | grep -e "Swarm:\s*active\s*" >/dev/null 2>&1; then
|
||||
if docker info 2>/dev/null | grep "Expiry Duration: 2 days"; then
|
||||
pass -c "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
info -c "$check"
|
||||
logcheckresult "INFO"
|
||||
return
|
||||
fi
|
||||
pass -c "$check (Swarm mode not enabled)"
|
||||
logcheckresult "PASS"
|
||||
}
|
||||
|
||||
check_7_8() {
|
||||
local id="7.8"
|
||||
local desc="Ensure that CA certificates are rotated as appropriate (Manual)"
|
||||
local remediation="You should run the command docker swarm ca --rotate to rotate a certificate."
|
||||
local remediationImpact="None."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
if docker info 2>/dev/null | grep -e "Swarm:\s*active\s*" >/dev/null 2>&1; then
|
||||
info -c "$check"
|
||||
logcheckresult "INFO"
|
||||
return
|
||||
fi
|
||||
pass -c "$check (Swarm mode not enabled)"
|
||||
logcheckresult "PASS"
|
||||
}
|
||||
|
||||
check_7_9() {
|
||||
local id="7.9"
|
||||
local desc="Ensure that management plane traffic is separated from data plane traffic (Manual)"
|
||||
local remediation="You should initialize the swarm with dedicated interfaces for management and data planes respectively. Example: docker swarm init --advertise-addr=192.168.0.1 --data-path-addr=17.1.0.3"
|
||||
local remediationImpact="This requires two network interfaces per node."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
if docker info 2>/dev/null | grep -e "Swarm:\s*active\s*" >/dev/null 2>&1; then
|
||||
info -c "$check"
|
||||
logcheckresult "INFO"
|
||||
return
|
||||
fi
|
||||
pass -c "$check (Swarm mode not enabled)"
|
||||
logcheckresult "PASS"
|
||||
}
|
||||
|
||||
check_7_end() {
|
||||
endsectionjson
|
||||
}
|
170
tests/8_docker_enterprise_configuration.sh
Normal file
170
tests/8_docker_enterprise_configuration.sh
Normal file
|
@ -0,0 +1,170 @@
|
|||
#!/bin/bash
|
||||
|
||||
check_8() {
|
||||
logit ""
|
||||
local id="8"
|
||||
local desc="Docker Enterprise Configuration"
|
||||
checkHeader="$id - $desc"
|
||||
info "$checkHeader"
|
||||
startsectionjson "$id" "$desc"
|
||||
}
|
||||
|
||||
check_product_license() {
|
||||
enterprise_license=1
|
||||
if docker version | grep -Eqi '^Server.*Community$|Version.*-ce$'; then
|
||||
info " * Community Engine license, skipping section 8"
|
||||
enterprise_license=0
|
||||
fi
|
||||
}
|
||||
|
||||
check_8_1() {
|
||||
if [ "$enterprise_license" -ne 1 ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
local id="8.1"
|
||||
local desc="Universal Control Plane Configuration"
|
||||
local check="$id - $desc"
|
||||
info "$check"
|
||||
}
|
||||
|
||||
check_8_1_1() {
|
||||
if [ "$enterprise_license" -ne 1 ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
local id="8.1.1"
|
||||
local desc="Configure the LDAP authentication service (Automated)"
|
||||
local remediation="You can configure LDAP integration via the UCP Admin Settings UI. LDAP integration can also be enabled via a configuration file"
|
||||
local remediationImpact="None."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
note -c "$check"
|
||||
logcheckresult "INFO"
|
||||
}
|
||||
|
||||
check_8_1_2() {
|
||||
if [ "$enterprise_license" -ne 1 ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
local id="8.1.2"
|
||||
local desc="Use external certificates (Automated)"
|
||||
local remediation="You can configure your own certificates for UCP either during installation or after installation via the UCP Admin Settings user interface."
|
||||
local remediationImpact="None."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
note -c "$check"
|
||||
logcheckresult "INFO"
|
||||
}
|
||||
|
||||
check_8_1_3() {
|
||||
if [ "$enterprise_license" -ne 1 ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
local id="8.1.3"
|
||||
local desc="Enforce the use of client certificate bundles for unprivileged users (Not Scored)"
|
||||
local remediation="Client certificate bundles can be created in one of two ways. User Management UI: UCP Administrators can provision client certificate bundles on behalf of users. Self-Provision: Users with access to the UCP console can create client certificate bundles themselves."
|
||||
local remediationImpact="None."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
note -c "$check"
|
||||
logcheckresult "INFO"
|
||||
}
|
||||
|
||||
check_8_1_4() {
|
||||
if [ "$enterprise_license" -ne 1 ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
local id="8.1.4"
|
||||
local desc="Configure applicable cluster role-based access control policies (Not Scored)"
|
||||
local remediation="UCP RBAC components can be configured as required via the UCP User Management UI."
|
||||
local remediationImpact="None."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
note -c "$check"
|
||||
logcheckresult "INFO"
|
||||
}
|
||||
|
||||
check_8_1_5() {
|
||||
if [ "$enterprise_license" -ne 1 ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
local id="8.1.5"
|
||||
local desc="Enable signed image enforcement (Automated)"
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
note -c "$check"
|
||||
logcheckresult "INFO"
|
||||
}
|
||||
|
||||
check_8_1_6() {
|
||||
if [ "$enterprise_license" -ne 1 ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
local id="8.1.6"
|
||||
local desc="Set the Per-User Session Limit to a value of '3' or lower (Automated)"
|
||||
local remediation="Retrieve a UCP API token. Retrieve and save UCP config. Open the ucp-config.toml file, set the per_user_limit entry under the [auth.sessions] section to a value of 3 or lower, but greater than 0. Update UCP with the new configuration."
|
||||
local remediationImpact="None."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
note -c "$check"
|
||||
logcheckresult "INFO"
|
||||
}
|
||||
|
||||
check_8_1_7() {
|
||||
if [ "$enterprise_license" -ne 1 ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
local id="8.1.7"
|
||||
local desc="Set the 'Lifetime Minutes' and 'Renewal Threshold Minutes' values to '15' or lower and '0' respectively (Automated)"
|
||||
local remediation="Retrieve a UCP API token. Retrieve and save UCP config. Open the ucp-config.toml file, set the lifetime_minutes and renewal_threshold_minutes entries under the [auth.sessions] section to values of 15 or lower and 0 respectively. Update UCP with the new configuration."
|
||||
local remediationImpact="Setting the Lifetime Minutes setting to a value that is too lower would result in users having to constantly re-authenticate to their Docker Enterprise cluster."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
note -c "$check"
|
||||
logcheckresult "INFO"
|
||||
}
|
||||
|
||||
check_8_2() {
|
||||
if [ "$enterprise_license" -ne 1 ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
local id="8.2"
|
||||
local desc="Docker Trusted Registry Configuration"
|
||||
local check="$id - $desc"
|
||||
info "$check"
|
||||
}
|
||||
|
||||
check_8_2_1() {
|
||||
if [ "$enterprise_license" -ne 1 ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
local id="8.2.1"
|
||||
local desc="Enable image vulnerability scanning (Automated)"
|
||||
local remediation="You can navigate to DTR Settings UI and select the Security tab to access the image scanning configuration. Select the Enable Scanning slider to enable this functionality."
|
||||
local remediationImpact="None."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
note -c "$check"
|
||||
logcheckresult "INFO"
|
||||
}
|
||||
|
||||
check_8_end() {
|
||||
endsectionjson
|
||||
}
|
234
tests/99_community_checks.sh
Normal file
234
tests/99_community_checks.sh
Normal file
|
@ -0,0 +1,234 @@
|
|||
#!/bin/bash
|
||||
|
||||
check_c() {
|
||||
logit ""
|
||||
local id="99"
|
||||
local desc="Community contributed checks"
|
||||
checkHeader="$id - $desc"
|
||||
info "$checkHeader"
|
||||
startsectionjson "$id" "$desc"
|
||||
}
|
||||
|
||||
check_c_1() {
|
||||
local id="C.1"
|
||||
local desc="This is a example check for a Automated check"
|
||||
local remediation="This is an example remediation measure for a Automated check"
|
||||
local remediationImpact="This is an example remediation impact for a Automated check"
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
if docker info --format='{{ .Architecture }}' | grep 'x86_64' 2>/dev/null 1>&2; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
if docker info --format='{{ .Architecture }}' | grep 'aarch64' 2>/dev/null 1>&2; then
|
||||
info -c "$check"
|
||||
logcheckresult "INFO"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
}
|
||||
|
||||
check_c_1_1() {
|
||||
local id="C.1.1"
|
||||
local desc="This is a example check for a Manual check"
|
||||
local remediation="This is an example remediation measure for a Manual check"
|
||||
local remediationImpact="This is an example remediation impact for a Manual check"
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
if docker info --format='{{ .Architecture }}' | grep 'x86_64' 2>/dev/null 1>&2; then
|
||||
pass -c "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
if docker info --format='{{ .Architecture }}' | grep 'aarch64' 2>/dev/null 1>&2; then
|
||||
info -c "$check"
|
||||
logcheckresult "INFO"
|
||||
return
|
||||
fi
|
||||
warn -c "$check"
|
||||
logcheckresult "WARN"
|
||||
}
|
||||
|
||||
check_c_2() {
|
||||
docker_version=$(docker version | grep -i -A2 '^server' | grep ' Version:' \
|
||||
| awk '{print $NF; exit}' | tr -d '[:alpha:]-,.' | cut -c 1-4)
|
||||
|
||||
local id="C.2"
|
||||
local desc="Ensure operations on legacy registry (v1) are Disabled"
|
||||
local remediation="Start docker daemon with --disable-legacy-registry=false flag. Starting with Docker 17.12, support for V1 registries has been removed, and the --disable-legacy-registry flag can no longer be used."
|
||||
local remediationImpact="Prevents the docker daemon from pull, push, and login operations against v1 registries."
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
if [ "$docker_version" -lt 1712 ]; then
|
||||
if get_docker_configuration_file_args 'disable-legacy-registry' | grep 'true' >/dev/null 2>&1; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
if get_docker_effective_command_line_args '--disable-legacy-registry' | grep "disable-legacy-registry" >/dev/null 2>&1; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
warn -s "$check"
|
||||
logcheckresult "WARN"
|
||||
return
|
||||
fi
|
||||
local desc="$desc (Deprecated)"
|
||||
local check="$id - $desc"
|
||||
info -c "$check"
|
||||
logcheckresult "INFO"
|
||||
}
|
||||
|
||||
check_c_5_3_1() {
|
||||
local id="C.5.3.1"
|
||||
local desc="Ensure that CAP_DAC_READ_SEARCH Linux kernel capability is disabled (Automated)"
|
||||
local remediation="Please refer to https://github.com/cdk-team/CDK/wiki/Exploit:-cap-dac-read-search for PoC."
|
||||
local remediationImpact=""
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
fail=0
|
||||
caps_containers=""
|
||||
for c in $containers; do
|
||||
container_caps=$(docker inspect --format 'CapAdd={{ .HostConfig.CapAdd }}' "$c")
|
||||
caps=$(echo "$container_caps" | tr "[:lower:]" "[:upper:]" | \
|
||||
sed 's/CAPADD/CapAdd/')
|
||||
if echo "$caps" | grep -q "DAC_READ_SEARCH"; then
|
||||
# If it's the first container, fail the test
|
||||
if [ $fail -eq 0 ]; then
|
||||
warn -s "$check"
|
||||
warn " * CAP_DAC_READ_SEARCH added to $c"
|
||||
caps_containers="$caps_containers $c"
|
||||
fail=1
|
||||
continue
|
||||
fi
|
||||
warn " * CAP_DAC_READ_SEARCH added to $c"
|
||||
caps_containers="$caps_containers $c"
|
||||
fi
|
||||
done
|
||||
# We went through all the containers and found none with extra capabilities
|
||||
if [ $fail -eq 0 ]; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
logcheckresult "WARN" "CAP_DAC_READ_SEARCH capability added for containers" "$caps_containers"
|
||||
}
|
||||
|
||||
check_c_5_3_2() {
|
||||
local id="C.5.3.2"
|
||||
local desc="Ensure that CAP_SYS_MODULE Linux kernel capability is disabled (Automated)"
|
||||
local remediation="Please refer to https://xcellerator.github.io/posts/docker_escape/ for PoC."
|
||||
local remediationImpact=""
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
fail=0
|
||||
caps_containers=""
|
||||
for c in $containers; do
|
||||
container_caps=$(docker inspect --format 'CapAdd={{ .HostConfig.CapAdd }}' "$c")
|
||||
caps=$(echo "$container_caps" | tr "[:lower:]" "[:upper:]" | \
|
||||
sed 's/CAPADD/CapAdd/')
|
||||
if echo "$caps" | grep -q "SYS_MODULE"; then
|
||||
# If it's the first container, fail the test
|
||||
if [ $fail -eq 0 ]; then
|
||||
warn -s "$check"
|
||||
warn " * CAP_SYS_MODULE added to $c"
|
||||
caps_containers="$caps_containers $c"
|
||||
fail=1
|
||||
continue
|
||||
fi
|
||||
warn " * CAP_SYS_MODULE added to $c"
|
||||
caps_containers="$caps_containers $c"
|
||||
fi
|
||||
done
|
||||
# We went through all the containers and found none with extra capabilities
|
||||
if [ $fail -eq 0 ]; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
logcheckresult "WARN" "CAP_SYS_MODULE capability added for containers" "$caps_containers"
|
||||
}
|
||||
|
||||
check_c_5_3_3() {
|
||||
local id="C.5.3.3"
|
||||
local desc="Ensure that CAP_SYS_ADMIN Linux kernel capability is disabled (Automated)"
|
||||
local remediation="Please refer to https://blog.trailofbits.com/2019/07/19/understanding-docker-container-escapes/ for PoC."
|
||||
local remediationImpact=""
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
fail=0
|
||||
caps_containers=""
|
||||
for c in $containers; do
|
||||
container_caps=$(docker inspect --format 'CapAdd={{ .HostConfig.CapAdd }}' "$c")
|
||||
caps=$(echo "$container_caps" | tr "[:lower:]" "[:upper:]" | \
|
||||
sed 's/CAPADD/CapAdd/')
|
||||
if echo "$caps" | grep -q "SYS_ADMIN"; then
|
||||
# If it's the first container, fail the test
|
||||
if [ $fail -eq 0 ]; then
|
||||
warn -s "$check"
|
||||
warn " * CAP_SYS_ADMIN added to $c"
|
||||
caps_containers="$caps_containers $c"
|
||||
fail=1
|
||||
continue
|
||||
fi
|
||||
warn " * CAP_SYS_ADMIN added to $c"
|
||||
caps_containers="$caps_containers $c"
|
||||
fi
|
||||
done
|
||||
# We went through all the containers and found none with extra capabilities
|
||||
if [ $fail -eq 0 ]; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
logcheckresult "WARN" "CAP_SYS_ADMIN capability added for containers" "$caps_containers"
|
||||
}
|
||||
|
||||
check_c_5_3_4() {
|
||||
local id="C.5.3.4"
|
||||
local desc="Ensure that CAP_SYS_PTRACE Linux kernel capability is disabled (Automated)"
|
||||
local remediation="Please refer to https://0xn3va.gitbook.io/cheat-sheets/container/escaping/excessive-capabilities#cap_sys_ptrace"
|
||||
local remediationImpact=""
|
||||
local check="$id - $desc"
|
||||
starttestjson "$id" "$desc"
|
||||
|
||||
fail=0
|
||||
caps_containers=""
|
||||
for c in $containers; do
|
||||
container_caps=$(docker inspect --format 'CapAdd={{ .HostConfig.CapAdd }}' "$c")
|
||||
caps=$(echo "$container_caps" | tr "[:lower:]" "[:upper:]" | \
|
||||
sed 's/CAPADD/CapAdd/')
|
||||
if echo "$caps" | grep -q "SYS_PTRACE"; then
|
||||
# If it's the first container, fail the test
|
||||
if [ $fail -eq 0 ]; then
|
||||
warn -s "$check"
|
||||
warn " * CAP_SYS_PTRACE added to $c"
|
||||
caps_containers="$caps_containers $c"
|
||||
fail=1
|
||||
continue
|
||||
fi
|
||||
warn " * CAP_SYS_PTRACE added to $c"
|
||||
caps_containers="$caps_containers $c"
|
||||
fi
|
||||
done
|
||||
# We went through all the containers and found none with extra capabilities
|
||||
if [ $fail -eq 0 ]; then
|
||||
pass -s "$check"
|
||||
logcheckresult "PASS"
|
||||
return
|
||||
fi
|
||||
logcheckresult "WARN" "CAP_SYS_PTRACE capability added for containers" "$caps_containers"
|
||||
}
|
||||
|
||||
check_c_end() {
|
||||
endsectionjson
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue