Skip to content
This repository has been archived by the owner on Jul 20, 2022. It is now read-only.

Commit

Permalink
feat: Non-root user support via S6 overlay, automated tests added
Browse files Browse the repository at this point in the history
  • Loading branch information
lholota committed Jan 29, 2020
1 parent 753b5e9 commit ec192e6
Show file tree
Hide file tree
Showing 32 changed files with 616 additions and 19 deletions.
4 changes: 3 additions & 1 deletion .gitattributes
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
* text=auto
*.sh eol=lf
*.sh eol=lf
**/run eol=lf
*/services.d/* eol=lf
8 changes: 8 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master

- name: Set up java for tests execution
uses: actions/setup-java@v1
with:
java-version: 11

- name: Set tag var
id: vars
Expand All @@ -24,6 +29,9 @@ jobs:
- name: Build Docker image
run: docker build . --file Dockerfile --tag ${{ env.IMAGE_NAME }}:${{ steps.vars.outputs.docker_tag }} --label quay.expires-after=2h

- name: Test Docker image
run: chmod 777 example && cd tests && gradle test -Dimage_tag=${{ env.IMAGE_NAME }}:${{ steps.vars.outputs.docker_tag }}

- name: Scan with Phonito Security
uses: phonito/phonito-scanner-action@master
with:
Expand Down
6 changes: 6 additions & 0 deletions .github/workflows/ci_cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ jobs:
--label "version=$RELEASE_VERSION" \
--label "org.label-schema.build-date=$(date '+%F %T')"
- name: Test Docker image
run: docker-compose up --exit-code-from test

- name: Test Docker image
run: chmod 777 example && cd tests && gradle test -Dimage_tag=${{ env.IMAGE_NAME }}:${{ env.RELEASE_VERSION }}

- name: Scan with Phonito Security
if: env.RELEASE_VERSION != ''
uses: phonito/phonito-scanner-action@master
Expand Down
20 changes: 20 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,23 @@
**/*.bind
**/*.bind.jnl
node_modules

*.class
*.jar
*.war
*.ear
.gradle
build
.gradletasknamecache

**/.idea/workspace.xml
**/.idea/tasks.xml

# Ignore Gradle GUI config
gradle-app.setting

# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
!gradle-wrapper.jar

# Cache of project
.gradletasknamecache
23 changes: 13 additions & 10 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
FROM homecentr/base:1.0.0 as base

FROM alpine:3.11.2

LABEL maintainer="Lukas Holota <[email protected]>"

RUN apk add --no-cache bind=9.14.8-r5 libcap=2.27-r0 && \
# Create directory for built-in configs
mkdir /config-default && \
# Prepare directory for pid file so that also non-root user can write into it
chmod 0757 /var/run/named && \
# Copy S6 overlay and shared scripts
COPY --from=base / /

# Copy S6 scripts & default configs
COPY ./fs/ /

RUN apk add --no-cache \
bind=9.14.8-r5 \
libcap=2.27-r0 \
shadow=4.7-r1 && \
# Grant the named process to open a well-known port (1-1024) which normally requires root permissions
setcap 'cap_net_bind_service=+ep' /usr/sbin/named

COPY ./config/named.conf /config-default/
COPY ./config/healthcheck.conf /config-default/
COPY ./config/healthcheck.zone /config-default/

HEALTHCHECK --interval=10s --timeout=3s --start-period=10s --retries=3 CMD [ "nslookup", "ns1.bind9-healthcheck", "127.0.0.1" ]

# Config directory
Expand All @@ -28,4 +31,4 @@ EXPOSE 953/tcp
# Default statistics port, not opened by default, must be configured
EXPOSE 8888/tcp

ENTRYPOINT ["/usr/sbin/named", "-f", "-g", "-4", "-c", "/config-default/named.conf"]
ENTRYPOINT ["/init"]
26 changes: 22 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ This container contains the [BIND9 DNS server](https://www.isc.org/bind/).

## Project status

TODO: Remove snyk, replace with Phonito - link to actions

| Project status/quality | Analytics |
|--------|---------------|
| ![](https://snyk.io/test/github/homecentr/docker-dns/badge.svg) | [![](https://img.shields.io/docker/pulls/homecentr/dns.svg)](https://hub.docker.com/repository/docker/homecentr/dns) |
| [![](https://img.shields.io/github/issues-raw/homecentr/docker-dns/bug?label=open%20bugs)](https://github.com/homecentr/docker-dns/labels/bug) | [![](https://images.microbadger.com/badges/version/homecentr/dns.svg)](https://hub.docker.com/repository/docker/homecentr/dns) |
| [![](https://img.shields.io/github/license/homecentr/docker-dns)](https://github.com/homecentr/docker-dns/blob/master/LICENSE) |
| [![](https://img.shields.io/github/issues-raw/homecentr/docker-dns/bug?label=open%20bugs)](https://github.com/homecentr/docker-dns/labels/bug) | [![](https://img.shields.io/docker/pulls/homecentr/dns.svg)](https://hub.docker.com/repository/docker/homecentr/dns) |
| [![](https://img.shields.io/github/license/homecentr/docker-dns)](https://github.com/homecentr/docker-dns/blob/master/LICENSE) | [![](https://images.microbadger.com/badges/version/homecentr/dns.svg)](https://hub.docker.com/repository/docker/homecentr/dns) |
| [![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg)](https://github.com/homecentr/docker-dns/graphs/commit-activity) |
| ![](https://github.com/homecentr/docker-dns/workflows/CI%2FCD%20on%20master/badge.svg) |

Expand Down Expand Up @@ -35,10 +36,27 @@ services:
### Configuration
See the `example/named.conf` for a quickstart or [BIND9 documentation](https://kb.isc.org/docs/aa-01031) for full configuration reference. The root configuration file (named.conf) is expected to be at `/config/named.conf`. The container contains a piece of built-in configuration which automatically sets up the statistics endpoint and a zone for health check.

> Please note that the directory with zone files must be writable. BIND creates journal files next to the zone files (this cannot be changed) and will fail if it cannot create them. Please refer to the Security section below for details on container UID/GID.
## Exposed ports

| Port | Description |
|------|-------------|
| 53/tcp | DNS protocol over TCP |
| 53/udp | DNS protocol over UDP |
| 8888/tcp | Default port for statistics, is not opened by default, must be configured in named.conf |
| 8888/tcp | Default port for statistics, is not opened by default, must be configured in named.conf |

## Security

### Vulnerabilities

The image is periodically (daily) scanned by Phonito.io for possible vulnerabilities. The results are publically available, just check the [output of the daily scan](https://github.com/homecentr/docker-dns/actions?query=workflow%3A%22Regular+Docker+image+vulnerability+scan%22).

### Container user
The container runs as non-root user created during the build with UID and GID **7001**. In case this collides with another image/user, you can rebuild the image using the command below and supply a custom UID and GID.

```bash
docker build . --build-arg UID=9999 --build-arg GID=8888
```

The container will not work if you try to change the UID/GID using the `docker run` because the process would not have access to the required files in the image itself.
28 changes: 24 additions & 4 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,33 @@ version: "3.7"
services:
dns:
build: .
user: 1050:1050
image: homecentr/dns
container_name: dns
dns:
- 127.0.0.1 # important for health check
restart: unless-stopped
volumes:
- "./example:/config:rw"
ports:
- 53:53/tcp
- 53:53/udp
- 9000:9000/tcp
- "53:53/tcp"
- "53:53/udp"
- "953:953/tcp"
- "8888:8888/tcp"

test:
build: ./tests
volumes:
- /var/run/docker.sock:/var/run/docker.sock:rw
environment:
TESTED_CONTAINER_NAME: dns
TESTED_CONTAINER_IP: 172.177.0.10
networks:
dummy:
ipv4_address: 172.177.0.20

networks:
dummy:
driver: bridge
ipam:
config:
- subnet: 172.177.0.0/16
5 changes: 5 additions & 0 deletions example/named.conf
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,9 @@ options {
8.8.8.8;
8.8.4.4;
};
};

zone test {
type master;
file "/config/test.zone";
};
11 changes: 11 additions & 0 deletions example/test.zone
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
$ORIGIN test.
$TTL 86400
@ SOA ns1.test. hostmaster.test. (
2001062501 ; serial
10
10
10
10 )
;
NS ns1.bind9-healthcheck.
some-record A 127.0.0.122
File renamed without changes.
File renamed without changes.
File renamed without changes.
4 changes: 4 additions & 0 deletions fs/etc/cont-init.d/20-file-permissions.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/with-contenv ash

chown -R nonroot:nonroot /var/run/named
chown -R nonroot:nonroot /config-default
3 changes: 3 additions & 0 deletions fs/etc/services.d/dns/finish
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/usr/bin/execlineb -S1

s6-svscanctl -t /var/run/s6/services
5 changes: 5 additions & 0 deletions fs/etc/services.d/dns/run
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/usr/bin/execlineb -P

s6-setuidgid nonroot

/usr/sbin/named -f -g -4 -c /config-default/named.conf
30 changes: 30 additions & 0 deletions tests/.classpath
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="bin/main" path="src/main/java">
<attributes>
<attribute name="gradle_scope" value="main"/>
<attribute name="gradle_used_by_scope" value="main,test"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="bin/main" path="src/main/resources">
<attributes>
<attribute name="gradle_scope" value="main"/>
<attribute name="gradle_used_by_scope" value="main,test"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="bin/test" path="src/test/java">
<attributes>
<attribute name="gradle_scope" value="test"/>
<attribute name="gradle_used_by_scope" value="test"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="bin/test" path="src/test/resources">
<attributes>
<attribute name="gradle_scope" value="test"/>
<attribute name="gradle_used_by_scope" value="test"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8/"/>
<classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer"/>
<classpathentry kind="output" path="bin/default"/>
</classpath>
2 changes: 2 additions & 0 deletions tests/.idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions tests/.idea/.name

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 19 additions & 0 deletions tests/.idea/gradle.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 20 additions & 0 deletions tests/.idea/jarRepositories.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions tests/.idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions tests/.idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 23 additions & 0 deletions tests/.project
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>docker-dns-tests</name>
<comment>Project tests created by Buildship.</comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.buildship.core.gradleprojectbuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.buildship.core.gradleprojectnature</nature>
</natures>
</projectDescription>
2 changes: 2 additions & 0 deletions tests/.settings/org.eclipse.buildship.core.prefs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
connection.project.dir=
eclipse.preferences.version=1
27 changes: 27 additions & 0 deletions tests/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
plugins {
id 'java'
}

group 'org.homecentr'
version '1.0-SNAPSHOT'

sourceCompatibility = 1.8

repositories {
mavenCentral()
}

dependencies {
testImplementation group: 'junit', name: 'junit', version: '4.12'
testImplementation "org.testcontainers:testcontainers:1.12.5"
testImplementation "dnsjava:dnsjava:2.1.9"
testImplementation group: 'org.slf4j', name: 'slf4j-api', version: '1.7.30'
testImplementation group: 'org.slf4j', name: 'slf4j-simple', version: '1.7.30'
}

test {
systemProperty 'image_tag', System.getProperty('image_tag')
afterTest { desc, result ->
logger.quiet "Executing test ${desc.name} [${desc.className}] with result: ${result.resultType}"
}
}
Binary file added tests/gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
5 changes: 5 additions & 0 deletions tests/gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\:https://services.gradle.org/distributions/gradle-5.2.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Loading

0 comments on commit ec192e6

Please sign in to comment.