docker security

This commit is contained in:
Graham McIntire 2025-06-15 11:06:24 -05:00
parent 0991c1eebc
commit ce6cef6605
2 changed files with 181 additions and 8 deletions

View file

@ -2,14 +2,21 @@ ARG ELIXIR_VERSION=1.18.4
ARG OTP_VERSION=27.2.4 ARG OTP_VERSION=27.2.4
ARG DEBIAN_VERSION=bullseye-20250520-slim ARG DEBIAN_VERSION=bullseye-20250520-slim
# Set default non-root user and group IDs
ARG USER_ID=1000
ARG GROUP_ID=1000
ARG BUILDER_IMAGE="hexpm/elixir:${ELIXIR_VERSION}-erlang-${OTP_VERSION}-debian-${DEBIAN_VERSION}" ARG BUILDER_IMAGE="hexpm/elixir:${ELIXIR_VERSION}-erlang-${OTP_VERSION}-debian-${DEBIAN_VERSION}"
ARG RUNNER_IMAGE="debian:${DEBIAN_VERSION}" ARG RUNNER_IMAGE="debian:${DEBIAN_VERSION}"
FROM ${BUILDER_IMAGE} AS builder FROM ${BUILDER_IMAGE} AS builder
# install build dependencies # install build dependencies
RUN apt-get update -y && apt-get install -y build-essential git \ RUN apt-get update -y && \
&& apt-get clean && rm -f /var/lib/apt/lists/*_* apt-get upgrade -y && \
apt-get install -y build-essential git && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# prepare build dir # prepare build dir
WORKDIR /app WORKDIR /app
@ -54,9 +61,34 @@ RUN mix release
# the compiled release and other runtime necessities # the compiled release and other runtime necessities
FROM ${RUNNER_IMAGE} FROM ${RUNNER_IMAGE}
# Add non-root user
RUN groupadd -r app && useradd -r -g app -s /usr/sbin/nologin -c "Docker image user" app
# Install security updates and required packages
RUN apt-get update -y && \ RUN apt-get update -y && \
apt-get install -y libstdc++6 openssl libncurses5 locales ca-certificates \ apt-get upgrade -y && \
&& apt-get clean && rm -f /var/lib/apt/lists/*_* apt-get install -y --no-install-recommends \
libstdc++6 \
openssl \
libncurses5 \
locales \
ca-certificates \
tini && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* && \
# Remove setuid and setgid permissions
find / -perm /6000 -type f -exec chmod a-s {} \; || true
# Create a non-root user and group
groupadd -g ${GROUP_ID} aprs && \
useradd -u ${USER_ID} -g aprs -s /bin/false -M aprs && \
# Secure system configurations
chmod 0600 /etc/login.defs && \
chmod 0600 /etc/passwd && \
chmod 0600 /etc/group && \
# Create and secure app directory
mkdir -p /app && \
chown aprs:aprs /app && \
chmod 0750 /app
# Set the locale # Set the locale
RUN sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && locale-gen RUN sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && locale-gen
@ -66,10 +98,20 @@ ENV LANGUAGE en_US:en
ENV LC_ALL en_US.UTF-8 ENV LC_ALL en_US.UTF-8
WORKDIR "/app" WORKDIR "/app"
RUN chown nobody /app
# set runner ENV # Set security-related environment variables
ENV MIX_ENV="prod" ENV MIX_ENV="prod" \
LANG=en_US.UTF-8 \
LANGUAGE=en_US:en \
LC_ALL=en_US.UTF-8 \
# Disable history files
HISTFILE=/dev/null \
# Prevent writing .erlang.cookie file
HOME=/dev/null \
# Add security headers
SECURITY_HEADERS="true" \
# Disable debug info in production
ERL_AFLAGS="+S 1:1 +A 1 +K true -kernel shell_history enabled -kernel shell_history_file_bytes 0"
# Only copy the final release from the build stage # Only copy the final release from the build stage
COPY --from=builder --chown=nobody:root /app/_build/${MIX_ENV}/rel/aprs ./ COPY --from=builder --chown=nobody:root /app/_build/${MIX_ENV}/rel/aprs ./
@ -81,7 +123,23 @@ USER nobody
# above and adding an entrypoint. See https://github.com/krallin/tini for details # above and adding an entrypoint. See https://github.com/krallin/tini for details
# ENTRYPOINT ["/tini", "--"] # ENTRYPOINT ["/tini", "--"]
CMD ["/app/bin/server"] # Add specific capabilities needed by the app
CMD ["sh", "-c", "umask 027 && /app/bin/server"]
# Add security-related metadata
LABEL org.opencontainers.image.vendor="APRS.me" \
org.opencontainers.image.title="APRS.me Server" \
org.opencontainers.image.description="APRS.me server with security hardening" \
org.opencontainers.image.version="${MIX_ENV}" \
org.opencontainers.image.created="$(date -u +'%Y-%m-%dT%H:%M:%SZ')" \
security.root-user="false" \
security.non-root-user="app" \
security.privileged="false"
# Add security configuration
EXPOSE 4000
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:4000/ || exit 1
# Security scan stage # Security scan stage
FROM aquasec/trivy:latest AS trivy FROM aquasec/trivy:latest AS trivy

115
security-policy.json Normal file
View file

@ -0,0 +1,115 @@
{
"securityPolicy": {
"version": "1.0",
"default": "deny",
"rules": {
"network": {
"outbound": {
"allow": [
{
"port": 443,
"protocol": "tcp",
"purpose": "HTTPS connections for IP geolocation and updates"
},
{
"port": 14580,
"protocol": "tcp",
"purpose": "APRS-IS connection"
}
]
},
"inbound": {
"allow": [
{
"port": 4000,
"protocol": "tcp",
"purpose": "Web application access"
},
{
"port": 14580,
"protocol": "tcp",
"purpose": "APRS-IS incoming connections"
}
]
}
},
"filesystem": {
"readonly": [
"/app",
"/etc"
],
"writable": [
"/tmp",
"/var/log"
],
"denied": [
"/proc",
"/sys",
"/dev"
]
},
"capabilities": {
"drop": [
"ALL"
],
"add": [
"NET_BIND_SERVICE"
]
},
"seccomp": {
"defaultAction": "SCMP_ACT_ERRNO",
"allowedCalls": [
"accept",
"bind",
"close",
"connect",
"dup",
"exit",
"exit_group",
"fcntl",
"futex",
"getcwd",
"getpid",
"ioctl",
"listen",
"lseek",
"mkdir",
"open",
"read",
"recv",
"recvfrom",
"recvmsg",
"rt_sigaction",
"rt_sigprocmask",
"rt_sigreturn",
"send",
"sendto",
"sendmsg",
"set_robust_list",
"socket",
"write"
]
},
"logging": {
"level": "info",
"auditEvents": [
"user-auth",
"network-access",
"file-access",
"process-exec"
]
}
},
"compliance": {
"standards": [
"CIS Docker Benchmark",
"NIST SP 800-190"
],
"auditing": {
"enabled": true,
"logPath": "/var/log/audit/",
"retention": "30d"
}
}
}
}