diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..d71f4037a88ea370faf0202c7519afbec6fd4a3a --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.nfs* +root/user/bin/.nfs* diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..3646244f68c5166734712138c1c30159dc20c449 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,56 @@ +ARG BASE_REGISTRY=registry1.dso.mil +ARG BASE_IMAGE=redhat/ubi/ubi8 +ARG BASE_TAG=8.3 + +FROM ${BASE_REGISTRY}/${BASE_IMAGE}:${BASE_TAG} + +# Set necessary environment variables for python and python development environment +ARG APP_ROOT=/opt/app-root +ENV PYTHON_VERSION=3.8 \ + APP_ROOT=$APP_ROOT \ + USER_NAME=hero \ + HOME=${APP_ROOT} \ + PATH=$HOME/.local/bin/:$APP_ROOT/.local/bin:/opt/app-root/src/bin:/opt/app-root/bin:$PATH: \ + EDITOR=/usr/bin/vim \ + PS1="AAP \W\$ " \ + PYTHONUNBUFFERED=1 \ + PYTHONIOENCODING=UTF-8 \ + PIP_NO_CACHE_DIR=off \ + LANG="en_US.UTF-8" + +# - Enable the virtual python environment and default interactive and non-interactive +# shell environment upon container startup +ENV PROMPT_COMMAND="" + +# Copy extra files to the image. +COPY ./scripts /usr/bin +RUN chmod a+x /usr/bin/container-entrypoint && \ + chmod a+x /usr/bin/fix-permissions && \ + chmod a+x /usr/bin/rpm-file-permissions && \ + chmod a+x /usr/bin/generate-container-user && \ + chmod a+x /usr/bin/py-enable + + +# Install packages +RUN INSTALL_PKGS="vim-enhanced rsync iputils bind-utils git python38 python38-devel python38-setuptools python38-pip " && \ + yum -y update-minimal --setopt=tsflags=nodocs --security && \ + yum -y --setopt=tsflags=nodocs install $INSTALL_PKGS && \ + yum -y remove vim-minimal && \ + rpm -V $INSTALL_PKGS && \ + yum -y clean all --enablerepo="*" + +# - Create a Python virtual environment for use by any application to avoid potential conflicts with Python packages +# preinstalled in the main Python installation. +RUN python$PYTHON_VERSION -m venv ${APP_ROOT} && /usr/bin/py-enable + +# Set up container user and adjust permissions to run in OpenShift environment +WORKDIR ${HOME} +RUN useradd -u 1001 -r -g 0 -d ${HOME} -s /sbin/nologin \ + -c "Default Application User" default && \ + fix-permissions ${APP_ROOT} -P && \ + fix-permissions ${HOME} -P && \ + rpm-file-permissions + +ENTRYPOINT ["/usr/bin/container-entrypoint"] + +HEALTHCHECK CMD python --version diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..61afe9ce006ff621fe731f6a560e5ed547788987 --- /dev/null +++ b/LICENSE @@ -0,0 +1,46 @@ + + + Python: + + PSF LICENSE AGREEMENT FOR PYTHON 3.6.12 +1. This LICENSE AGREEMENT is between the Python Software Foundation ("PSF"), and + the Individual or Organization ("Licensee") accessing and otherwise using Python + 3.6.12 software in source or binary form and its associated documentation. + +2. Subject to the terms and conditions of this License Agreement, PSF hereby + grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, + analyze, test, perform and/or display publicly, prepare derivative works, + distribute, and otherwise use Python 3.6.12 alone or in any derivative + version, provided, however, that PSF's License Agreement and PSF's notice of + copyright, i.e., "Copyright © 2001-2020 Python Software Foundation; All Rights + Reserved" are retained in Python 3.6.12 alone or in any derivative version + prepared by Licensee. + +3. In the event Licensee prepares a derivative work that is based on or + incorporates Python 3.6.12 or any part thereof, and wants to make the + derivative work available to others as provided herein, then Licensee hereby + agrees to include in any such work a brief summary of the changes made to Python + 3.6.12. + +4. PSF is making Python 3.6.12 available to Licensee on an "AS IS" basis. + PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF + EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY REPRESENTATION OR + WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE + USE OF PYTHON 3.6.12 WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. + +5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON 3.6.12 + FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF + MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 3.6.12, OR ANY DERIVATIVE + THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +6. This License Agreement will automatically terminate upon a material breach of + its terms and conditions. + +7. Nothing in this License Agreement shall be deemed to create any relationship + of agency, partnership, or joint venture between PSF and Licensee. This License + Agreement does not grant permission to use PSF trademarks or trade name in a + trademark sense to endorse or promote products or services of Licensee, or any + third party. + +8. By copying, installing or otherwise using Python 3.6.12, Licensee agrees + to be bound by the terms and conditions of this License Agreement. diff --git a/README.md b/README.md index 5dc6fa6db4361c22da2f35edf0544d83ba6001e2..14dc575298807731cbd33b4456208648a819c915 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,2 @@ -# - -Project template for all Iron Bank container repositories. \ No newline at end of file +# AAP Python base image +_Use as a base image for custom python apps._ diff --git a/hardening_manifest.yaml b/hardening_manifest.yaml new file mode 100644 index 0000000000000000000000000000000000000000..873532bb876c282b3432421e0206b7ac16efc19a --- /dev/null +++ b/hardening_manifest.yaml @@ -0,0 +1,44 @@ +apiVersion: v1 + +# The repository name in registry1, excluding /ironbank/ +name: "diat/aap-python" + +# List of tags to push for the repository in registry1 +# The most specific version should be the first tag and will be shown +# on ironbank.dso.mil +tags: +- "14.0" +- "latest" + +# Build args passed to Dockerfile ARGs +args: + BASE_REGISTRY: "registry1.dsop.io" + BASE_IMAGE: "redhat/ubi/ubi8" + BASE_TAG: "8.3" + +# Docker image labels +labels: + # Name of the image + org.opencontainers.image.title: "aap-python" + # Human-readable description of the software packaged in the image + org.opencontainers.image.description: "Python $PYTHON_VERSION available as container is a base platform for building and running various Python $PYTHON_VERSION applications and frameworks." + # License(s) under which contained software is distributed + org.opencontainers.image.licenses: "AAP License" + # URL to find more information on the image + org.opencontainers.image.url: "https://wiki.navair1.navy.mil/display/Analytics/Advanced+Analytics+Platform" + # Name of the distributing entity, organization or individual + org.opencontainers.image.vendor: "aap-python" + # Authoritative version of the software + org.opencontainers.image.version: "14.0" + # Keywords to help with search (ex. "cicd,gitops,golang") + mil.dso.ironbank.image.keywords: "aap,python,aappython,aap-python,pythonent,atlas,diat" + # This value can be "opensource" or "commercial" + mil.dso.ironbank.image.type: "commercial" + # Product the image belongs to for grouping multiple images + mil.dso.ironbank.product.name: "diat/aap-python" + +# List of project maintainers +maintainers: +- email: "wingkwan.lau1@navy.mil" + name: "WingKwan Lau" + username: "wlau" diff --git a/scripts/container-entrypoint b/scripts/container-entrypoint new file mode 100644 index 0000000000000000000000000000000000000000..339a74c197880c01b98183e3bbe296d746ebfe02 --- /dev/null +++ b/scripts/container-entrypoint @@ -0,0 +1,9 @@ +#!/bin/bash + +# temp: hard coding "hero" as container username (todo: fix to use env vars for username and homedir) +if [ `id -u` -ge 1 ]; then + echo "hero:x:`id -u`:`id -g`:here:/opt/app-root:/bin/bash" >> /etc/passwd +fi + +exec "$@" + diff --git a/scripts/fix-permissions b/scripts/fix-permissions new file mode 100644 index 0000000000000000000000000000000000000000..827eeb587616115c2c025e6e2e45140034b295be --- /dev/null +++ b/scripts/fix-permissions @@ -0,0 +1,28 @@ +#!/bin/sh + +# Allow this script to fail without failing a build +set +e + +SYMLINK_OPT=${2:--L} + +# Fix permissions on the given directory or file to allow group read/write of +# regular files and execute of directories. + +[ $(id -u) -ne 0 ] && CHECK_OWNER=" -uid $(id -u)" + +# If argument does not exist, script will still exit with 0, +# but at least we'll see something went wrong in the log +if ! [ -e "$1" ] ; then + echo "ERROR: File or directory $1 does not exist." >&2 + # We still want to end successfully + exit 0 +fi + +find $SYMLINK_OPT "$1" ${CHECK_OWNER} \! -gid 0 -exec chgrp 0 {} + +find $SYMLINK_OPT "$1" ${CHECK_OWNER} \! -perm -g+rw -exec chmod g+rw {} + +find $SYMLINK_OPT "$1" ${CHECK_OWNER} -perm /u+x -a \! -perm /g+x -exec chmod g+x {} + +find $SYMLINK_OPT "$1" ${CHECK_OWNER} -type d \! -perm /g+x -exec chmod g+x {} + + +# Always end successfully +exit 0 + diff --git a/scripts/generate-container-user b/scripts/generate-container-user new file mode 100644 index 0000000000000000000000000000000000000000..f092c51e489c1e05f918f1005e8bddf0925cc0da --- /dev/null +++ b/scripts/generate-container-user @@ -0,0 +1,20 @@ +# Set current user in nss_wrapper +USER_ID=$(id -u) +GROUP_ID=$(id -g) + +if [ x"$USER_ID" != x"0" -a x"$USER_ID" != x"1001" ]; then + + NSS_WRAPPER_PASSWD=/opt/app-root/etc/passwd + NSS_WRAPPER_GROUP=/etc/group + + cat /etc/passwd | sed -e 's/^default:/builder:/' > $NSS_WRAPPER_PASSWD + + echo "default:x:${USER_ID}:${GROUP_ID}:Default Application User:${HOME}:/sbin/nologin" >> $NSS_WRAPPER_PASSWD + + export NSS_WRAPPER_PASSWD + export NSS_WRAPPER_GROUP + + LD_PRELOAD=libnss_wrapper.so + export LD_PRELOAD +fi + diff --git a/scripts/py-enable b/scripts/py-enable new file mode 100644 index 0000000000000000000000000000000000000000..9d1443b8db5d244960007080387c9e6d02d7b7fd --- /dev/null +++ b/scripts/py-enable @@ -0,0 +1,6 @@ +# IMPORTANT: Do not add more content to this file unless you know what you are +# doing. This file is sourced everytime the shell session is opened. +# This will make the python libraries work out of the box. +unset BASH_ENV PROMPT_COMMAND ENV +source /opt/app-root/bin/activate + diff --git a/scripts/rpm-file-permissions b/scripts/rpm-file-permissions new file mode 100644 index 0000000000000000000000000000000000000000..e96e7053c25f03d7e55880d42074f18e11bd8be5 --- /dev/null +++ b/scripts/rpm-file-permissions @@ -0,0 +1,22 @@ +#!/bin/sh + +CHECK_DIRS="/ /opt /etc /usr /usr/bin /usr/lib /usr/lib64 /usr/share /usr/libexec" + +rpm_format="[%{FILESTATES:fstate} %7{FILEMODES:octal} %{FILENAMES:shescape}\n]" + +rpm -q --qf "$rpm_format" filesystem | while read line +do + eval "set -- $line" + + case $1 in + normal) ;; + *) continue ;; + esac + + case " $CHECK_DIRS " in + *" $3 "*) + chmod "${2: -4}" "$3" + ;; + esac +done +