diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index f99b8a2..0000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,10 +0,0 @@ -version: 2 -updates: - - package-ecosystem: "github-actions" - directory: "/" - schedule: - interval: "weekly" - open-pull-requests-limit: 0 - commit-message: - prefix: "chore" - include: "scope" diff --git a/.github/workflows/docker-build-push-legacy.yml b/.github/workflows/docker-build-push-legacy.yml new file mode 100644 index 0000000..f1ed57c --- /dev/null +++ b/.github/workflows/docker-build-push-legacy.yml @@ -0,0 +1,69 @@ +name: Build and publish legacy Docker images + +# filigran/python-fips and filigran/python-nodejs-fips, built from legacy/. Kept +# rebuilt so that consumers still tracking them receive Alpine updates while they +# migrate to the alpine-prefixed images. See the migration window in README.md. +on: + push: + branches: + - main + paths: + - legacy/** + - .github/workflows/docker-build-push-legacy.yml + pull_request: + paths: + - legacy/** + - .github/workflows/docker-build-push-legacy.yml + schedule: + # Offset from the main build, which these images share nothing with. + - cron: "0 2 * * *" + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: docker-build-push-legacy-${{ github.ref }} + cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} + +jobs: + build: + name: Build ${{ matrix.image }} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + include: + - image: filigran/python-fips + dockerfile: Dockerfile_python + tags: | + filigran/python-fips:python3.12 + filigran/python-fips:latest + - image: filigran/python-nodejs-fips + dockerfile: Dockerfile_python_nodejs + tags: | + filigran/python-nodejs-fips:python3.12-nodejs24 + filigran/python-nodejs-fips:latest + steps: + - name: Checkout repository + uses: actions/checkout@v7 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v4 + + - name: Log in to Docker Hub + if: github.ref == 'refs/heads/main' + uses: docker/login-action@v4 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Build ${{ matrix.image }} + uses: docker/build-push-action@v7 + with: + context: legacy + file: legacy/${{ matrix.dockerfile }} + platforms: linux/amd64 + pull: true + push: ${{ github.ref == 'refs/heads/main' }} + tags: ${{ matrix.tags }} diff --git a/.github/workflows/docker-build-push.yml b/.github/workflows/docker-build-push.yml index dbc5032..b5af454 100644 --- a/.github/workflows/docker-build-push.yml +++ b/.github/workflows/docker-build-push.yml @@ -4,6 +4,11 @@ on: push: branches: - main + paths-ignore: + - legacy/** + pull_request: + paths-ignore: + - legacy/** schedule: # Daily rebuild, to pick up upstream Alpine security updates. - cron: "0 0 * * *" @@ -12,49 +17,63 @@ on: permissions: contents: read +# A run that publishes must never be interrupted: the images share mutable tags, +# so two concurrent runs could push `latest` from two different builds, and a +# cancellation between the two build steps would publish one image and not the +# other. A run that publishes nothing is cancelled when superseded. concurrency: group: docker-build-push-${{ github.ref }} - cancel-in-progress: false + cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} jobs: build: - name: Build ${{ matrix.image }} + name: Build and publish runs-on: ubuntu-latest - timeout-minutes: 120 - strategy: - fail-fast: false - matrix: - include: - - image: filigran/python-fips - dockerfile: Dockerfile_python - tags: | - filigran/python-fips:python3.12 - filigran/python-fips:latest - - image: filigran/python-nodejs-fips - dockerfile: Dockerfile_python_nodejs - tags: | - filigran/python-nodejs-fips:python3.12-nodejs22 - filigran/python-nodejs-fips:latest steps: - name: Checkout repository uses: actions/checkout@v7 + # The Dockerfile asserts these versions at build time, so the tags are read + # from it rather than repeated here, where they could drift. + - name: Read the advertised versions + id: versions + run: | + set -euo pipefail + python=$(sed -n 's/^ARG PYTHON_VERSION=//p' Dockerfile) + nodejs=$(sed -n 's/^ARG NODEJS_VERSION=//p' Dockerfile) + test -n "${python}" && test -n "${nodejs}" + echo "python=${python}" >> "$GITHUB_OUTPUT" + echo "nodejs=${nodejs}" >> "$GITHUB_OUTPUT" + - name: Set up Docker Buildx uses: docker/setup-buildx-action@v4 - name: Log in to Docker Hub + if: github.ref == 'refs/heads/main' uses: docker/login-action@v4 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - - name: Build and push ${{ matrix.image }} + - name: Build filigran/alpine-python-fips uses: docker/build-push-action@v7 with: context: . - file: ${{ matrix.dockerfile }} + target: python-fips platforms: linux/amd64 pull: true - push: true - no-cache: true - tags: ${{ matrix.tags }} + push: ${{ github.ref == 'refs/heads/main' }} + tags: | + filigran/alpine-python-fips:python${{ steps.versions.outputs.python }} + filigran/alpine-python-fips:latest + + - name: Build filigran/alpine-python-nodejs-fips + uses: docker/build-push-action@v7 + with: + context: . + target: python-nodejs-fips + platforms: linux/amd64 + push: ${{ github.ref == 'refs/heads/main' }} + tags: | + filigran/alpine-python-nodejs-fips:python${{ steps.versions.outputs.python }}-nodejs${{ steps.versions.outputs.nodejs }} + filigran/alpine-python-nodejs-fips:latest diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..667113f --- /dev/null +++ b/Dockerfile @@ -0,0 +1,93 @@ +# syntax=docker/dockerfile:1 +FROM alpine:3.23 AS python-fips + +# Only source version validated under FIPS 140-3 (CMVP #4985). Must not be +# bumped automatically: any other version leaves the validated lineage. +ARG OPENSSL_FIPS_VERSION=3.1.2 +ARG OPENSSL_FIPS_SHA256=a0ce69b8b97ea6a35b96875235aa453b966ba3cba8af2de23657d8b6767d6539 + +ENV LANG=C.UTF-8 + +RUN << EOT + set -euxo pipefail + + apk add --no-cache ca-certificates openssl python3 py3-pip libffi + rm -f /usr/lib/python3.*/EXTERNALLY-MANAGED +EOT + +# fips.so is the cryptographic module: the boundary stops at it, and the OpenSSL +# libraries calling into it stay the ones packaged by Alpine. Hence +# 'make install_fips', which installs the module and its fipsmodule.cnf only. +# The checksum enforces unmodified source, a condition of the CMVP porting rule. +# +# cryptography is built from source as well: a pre-built wheel carries its own +# OpenSSL and would sit outside the boundary. +RUN << EOT + set -euxo pipefail + + apk add --no-cache --virtual .build-deps build-base perl linux-headers cargo pkgconfig python3-dev libffi-dev openssl-dev + + wget -O openssl.tar.gz "https://github.com/openssl/openssl/releases/download/openssl-${OPENSSL_FIPS_VERSION}/openssl-${OPENSSL_FIPS_VERSION}.tar.gz" + echo "${OPENSSL_FIPS_SHA256} openssl.tar.gz" | sha256sum -c - + tar -xf openssl.tar.gz + cd "openssl-${OPENSSL_FIPS_VERSION}" + # Install into the paths compiled into Alpine's libcrypto, so that enabling + # FIPS needs no environment variable. + ./Configure enable-fips --prefix=/usr --libdir=lib --openssldir=/etc/ssl + make -j"$(nproc)" + make install_fips + cd .. + rm -rf "openssl-${OPENSSL_FIPS_VERSION}" openssl.tar.gz + + pip install --no-cache-dir --no-binary cryptography cryptography + + apk del .build-deps + # pip's isolated build environment and cargo keep their own caches, which + # apk del does not cover. + rm -rf /root/.cache /root/.cargo +EOT + +COPY openssl.cnf /etc/ssl/openssl.cnf + +# Advertised by the published tags, so a drift in the Alpine package must fail +# the build rather than produce an image whose tag lies. +ARG PYTHON_VERSION=3.12 + +RUN << EOT + set -euxo pipefail + + python3 -V | grep "^Python ${PYTHON_VERSION}\." > /dev/null + + openssl list -providers + openssl list -providers | grep 'OpenSSL FIPS Provider' > /dev/null + openssl list -providers | grep -A2 fips | grep "version: ${OPENSSL_FIPS_VERSION}" > /dev/null + openssl dgst -sha256 /etc/ssl/openssl.cnf > /dev/null + + if echo test | openssl dgst -md5 > /dev/null 2>&1; then + echo 'MD5 was accepted: FIPS mode is not enforced' >&2 + exit 1 + fi + + python3 -c 'from cryptography.hazmat.backends.openssl.backend import backend; print(backend.openssl_version_text())' \ + | grep "$(openssl version | cut -d' ' -f2)" > /dev/null +EOT + + +FROM python-fips AS python-nodejs-fips + +# Advertised by the published tags, so a drift in the Alpine package must fail +# the build rather than produce an image whose tag lies. +ARG NODEJS_VERSION=24 + +# Node.js reaches the FIPS provider only through the system OpenSSL it is +# dynamically linked against, which the assertions below enforce. +RUN << EOT + set -euxo pipefail + + apk add --no-cache nodejs + + node -v | grep "^v${NODEJS_VERSION}\." > /dev/null + + test "$(node --enable-fips -p 'crypto.getFips()')" = '1' + ldd "$(which node)" | grep 'libssl.so.3' > /dev/null +EOT diff --git a/FIPS.md b/FIPS.md new file mode 100644 index 0000000..68fb2cb --- /dev/null +++ b/FIPS.md @@ -0,0 +1,92 @@ +# FIPS 140-3 posture of these images + +## OpenSSL FIPS provider 3.1.2, validated under CMVP #4985 + +All cryptography in these images goes through that module, at the validated +version, under a certificate valid until 10 March 2030. + +FIPS mode is active by default. No flag, environment variable or configuration +step is required. + +## Built from the validated sources, by the documented procedure + +The Security Policy addresses integrators who build the module into their +product, and gives them this procedure: + +``` +$ ./Configure enable-fips +$ make +$ make install_fips +``` + +That is what the `Dockerfile` runs, on the source tarball from openssl.org whose +SHA-256 is pinned and verified. `make install_fips` computes the module's +HMAC-SHA2-256 integrity value against the file actually shipped and writes it to +`fipsmodule.cnf`. Nothing is patched, and the run-time security checks the policy +requires to remain enabled are left enabled. + +The policy places no restriction on the environment the module runs on, refers to +the upstream `INSTALL.md` and `README-FIPS.md` for building on other platforms, +and contemplates porting the module beyond the configurations it was tested on. + +Only 3.1.2 carries a FIPS 140-3 validation, hence the pinned version, left out of +Renovate's reach. The other validated sources — 3.0.0, 3.0.8 and 3.0.9 under +certificate #4282 — are FIPS 140-2, and #4282 moves to the CMVP *Historical* list +on 21 September 2026. + +## Non-approved algorithms are refused, not substituted + +Only the `fips` and `base` providers are activated, with +`default_properties = fips=yes`. The `default` provider is not declared at all, +so a non-approved algorithm is refused rather than quietly served from outside +the module. Were `fips.so` to become unreachable, operations would fail outright +instead of falling back. + +The build asserts all of this, and fails rather than produce an image whose FIPS +mode is not effective. + +## Claims these images support + +* They perform cryptography through the OpenSSL FIPS provider 3.1.2, validated + under CMVP certificate #4985. +* The module is built from the validated source distribution, unmodified, by the + procedure documented in its Security Policy, with integrity verification and + self-tests enabled. +* FIPS mode is enforced: non-approved algorithms are refused, not substituted. + +## What falls outside the module + +**Python `hashlib` is not fully inside the module.** `hashlib.sha256()` resolves +to `_hashlib.HASH` and goes through it, but `hashlib.md5()` resolves to +`_md5.md5`, CPython's built-in implementation, which bypasses OpenSSL and is not +blocked by FIPS mode. This is upstream CPython behaviour. Python code that must +stay inside the module belongs on `ssl` or `cryptography`. + +**Statically linked crypto bypasses the module.** Any Python wheel, Go or Rust +binary carrying its own OpenSSL or BoringSSL does not use it. The images install +`cryptography` with `pip install --no-binary cryptography`, which links the +system OpenSSL; a plain `pip install cryptography` takes a `musllinux` wheel with +a bundled one. + +## Checking an image + +```bash +docker run --rm filigran/alpine-python-nodejs-fips:latest sh -c ' + openssl list -providers + node --enable-fips -p "crypto.getFips()" + python3 -c "import ssl; print(ssl.OPENSSL_VERSION)" + echo test | openssl dgst -md5 || echo "MD5 refused, as expected" +' +``` + +The provider reports **3.1.2** while the library reports the Alpine version. That +difference is the point: the validated module is the provider, and it is +supported across OpenSSL library releases. + +## References + +- [OpenSSL FIPS 140-3 validation announcement (3.1.2, cert #4985)](https://openssl-library.org/post/2025-03-11-fips-140-3/) +- [Security Policy for certificate #4985](https://csrc.nist.gov/CSRC/media/projects/cryptographic-module-validation-program/documents/security-policies/140sp4985.pdf) +- [OpenSSL: which versions are FIPS validated](https://openssl-library.org/source/) +- [CMVP certificate #4282 (FIPS 140-2, historical 21 Sept 2026)](https://csrc.nist.gov/projects/cryptographic-module-validation-program/certificate/4282) +- [OpenSSL `README-FIPS.md` — provider/library version compatibility](https://github.com/openssl/openssl/blob/master/README-FIPS.md) diff --git a/README.md b/README.md index 4578110..a5eedf9 100644 --- a/README.md +++ b/README.md @@ -1,30 +1,71 @@ -# 🐳 Docker FIPS for NodeJS and Python +# 🐳 Docker FIPS for Node.js and Python -[![Pulls](https://img.shields.io/docker/pulls/filigran/python-nodejs-fips.svg)](https://hub.docker.com/r/filigran/python-nodejs-fips/) -[![Pulls](https://img.shields.io/docker/pulls/filigran/python-fips.svg)](https://hub.docker.com/r/filigran/python-fips/) +[![Pulls](https://img.shields.io/docker/pulls/filigran/alpine-python-nodejs-fips.svg)](https://hub.docker.com/r/filigran/alpine-python-nodejs-fips/) +[![Pulls](https://img.shields.io/docker/pulls/filigran/alpine-python-fips.svg)](https://hub.docker.com/r/filigran/alpine-python-fips/) [![Build](https://github.com/FiligranHQ/docker-python-nodejs-fips/actions/workflows/docker-build-push.yml/badge.svg)](https://github.com/FiligranHQ/docker-python-nodejs-fips/actions/workflows/docker-build-push.yml) -## Docker Python NodeJS FIPS +Alpine-based images running Python and Node.js against the OpenSSL FIPS provider +built from **FIPS 140-3 validated sources** (CMVP certificate #4985). -Images are available at: https://hub.docker.com/r/filigran/python-nodejs-fips. +OpenSSL, Python and Node.js come from Alpine packages; only the FIPS provider is +compiled. See [`FIPS.md`](FIPS.md) for the exact compliance posture before making +any claim. + +## Docker Python Node.js FIPS + +Images are available at: https://hub.docker.com/r/filigran/alpine-python-nodejs-fips. ## Docker Python FIPS -Images are available at: https://hub.docker.com/r/filigran/python-fips. +Images are available at: https://hub.docker.com/r/filigran/alpine-python-fips. + +## Migrating from `filigran/python-fips` and `filigran/python-nodejs-fips` + +Those two images are still built daily, from `legacy/`, so that consumers +tracking them keep receiving updates while they migrate. They are a migration +window, not a maintained line: their FIPS provider is built from the same sources +as the OpenSSL libraries and therefore carries **no CMVP certificate** — which is +what the images above fix. The legacy workflow is meant to be deleted. + +What changes when moving to the images above: + +* `npm` and `yarn` are gone, and so is the build toolchain (`rust`, `cargo`, + `gcc`) — an image that compiles native wheels has to install its own. +* The FIPS provider comes from the OpenSSL 3.1.2 validated sources instead of the + same version as the libraries, so the set of accepted algorithms differs. +* Node.js is 24, which the tag now states. ## Use the images -* For Python, bindings are automatically mapped to the OpenSSL FIPS 140-2 library, just run your Python scripts as usual. -* For NodeJS, ensure to run your NodeJS programs with `--enable-fips` or `--force-fips`. +* For Python, bindings are automatically mapped to the OpenSSL FIPS provider, + just run your Python scripts as usual. +* For Node.js, ensure to run your Node.js programs with `--enable-fips` or + `--force-fips`. +* When installing `cryptography`, use `pip install --no-binary cryptography` so + that it links the system OpenSSL instead of a bundled one. ## Proof of Concept / testing ```bash -$ docker run -it filigran/python-nodejs-fips:latest /bin/sh -$ openssl version -OpenSSL 3.1.5 30 Jan 2024 (Library: OpenSSL 3.1.5 30 Jan 2024) +$ docker run -it filigran/alpine-python-nodejs-fips:latest /bin/sh +$ openssl list -providers +Providers: + base + name: OpenSSL Base Provider + version: 3.5.7 + status: active + fips + name: OpenSSL FIPS Provider + version: 3.1.2 + status: active $ node --enable-fips -p 'crypto.getFips()' 1 $ python3 -c "import ssl; print(ssl.OPENSSL_VERSION);" -OpenSSL 3.1.5 30 Jan 2024 -``` \ No newline at end of file +OpenSSL 3.5.7 9 Jun 2026 +$ echo test | openssl dgst -md5 +Error setting digest +``` + +The FIPS provider reports `3.1.2` while the library reports the Alpine version. +That difference is expected: the validated module is the provider, and it is +supported across OpenSSL library releases. diff --git a/Dockerfile_python b/legacy/Dockerfile_python similarity index 100% rename from Dockerfile_python rename to legacy/Dockerfile_python diff --git a/Dockerfile_python_nodejs b/legacy/Dockerfile_python_nodejs similarity index 100% rename from Dockerfile_python_nodejs rename to legacy/Dockerfile_python_nodejs diff --git a/legacy/openssl.cnf b/legacy/openssl.cnf new file mode 100644 index 0000000..ccd1225 --- /dev/null +++ b/legacy/openssl.cnf @@ -0,0 +1,389 @@ +# +# OpenSSL example configuration file. +# See doc/man5/config.pod for more info. +# +# This is mostly being used for generation of certificate requests, +# but may be used for auto loading of providers + +# Note that you can include other files from the main configuration +# file using the .include directive. +#.include filename + +# This definition stops the following lines choking if HOME isn't +# defined. +HOME = . + +# Use this in order to automatically load providers. +openssl_conf = openssl_init + +# For NodeJS +nodejs_conf = nodejs_init + +# Comment out the next line to ignore configuration errors +config_diagnostics = 1 + +# Extra OBJECT IDENTIFIER info: +# oid_file = $ENV::HOME/.oid +oid_section = new_oids + +# To use this configuration file with the "-extfile" option of the +# "openssl x509" utility, name here the section containing the +# X.509v3 extensions to use: +# extensions = +# (Alternatively, use a configuration file that has only +# X.509v3 extensions in its main [= default] section.) + +[ new_oids ] +# We can add new OIDs in here for use by 'ca', 'req' and 'ts'. +# Add a simple OID like this: +# testoid1=1.2.3.4 +# Or use config file substitution like this: +# testoid2=${testoid1}.5.6 + +# Policies used by the TSA examples. +tsa_policy1 = 1.2.3.4.1 +tsa_policy2 = 1.2.3.4.5.6 +tsa_policy3 = 1.2.3.4.5.7 + +# For FIPS +# Optionally include a file that is generated by the OpenSSL fipsinstall +# application. This file contains configuration data required by the OpenSSL +# fips provider. It contains a named section e.g. [fips_sect] which is +# referenced from the [provider_sect] below. +# Refer to the OpenSSL security policy for more information. +.include /usr/local/ssl/fipsmodule.cnf + +[openssl_init] +providers = provider_sect +alg_section = algorithm_sect + +[nodejs_init] +providers = provider_sect + +[provider_sect] +fips = fips_sect +base = base_sect + +[base_sect] +activate = 1 + +[algorithm_sect] +default_properties = fips=yes + + +#################################################################### +[ ca ] +default_ca = CA_default # The default ca section + +#################################################################### +[ CA_default ] + +dir = ./demoCA # Where everything is kept +certs = $dir/certs # Where the issued certs are kept +crl_dir = $dir/crl # Where the issued crl are kept +database = $dir/index.txt # database index file. +#unique_subject = no # Set to 'no' to allow creation of + # several certs with same subject. +new_certs_dir = $dir/newcerts # default place for new certs. + +certificate = $dir/cacert.pem # The CA certificate +serial = $dir/serial # The current serial number +crlnumber = $dir/crlnumber # the current crl number + # must be commented out to leave a V1 CRL +crl = $dir/crl.pem # The current CRL +private_key = $dir/private/cakey.pem# The private key + +x509_extensions = usr_cert # The extensions to add to the cert + +# Comment out the following two lines for the "traditional" +# (and highly broken) format. +name_opt = ca_default # Subject Name options +cert_opt = ca_default # Certificate field options + +# Extension copying option: use with caution. +# copy_extensions = copy + +# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs +# so this is commented out by default to leave a V1 CRL. +# crlnumber must also be commented out to leave a V1 CRL. +# crl_extensions = crl_ext + +default_days = 365 # how long to certify for +default_crl_days= 30 # how long before next CRL +default_md = default # use public key default MD +preserve = no # keep passed DN ordering + +# A few difference way of specifying how similar the request should look +# For type CA, the listed attributes must be the same, and the optional +# and supplied fields are just that :-) +policy = policy_match + +# For the CA policy +[ policy_match ] +countryName = match +stateOrProvinceName = match +organizationName = match +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +# For the 'anything' policy +# At this point in time, you must list all acceptable 'object' +# types. +[ policy_anything ] +countryName = optional +stateOrProvinceName = optional +localityName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +#################################################################### +[ req ] +default_bits = 2048 +default_keyfile = privkey.pem +distinguished_name = req_distinguished_name +attributes = req_attributes +x509_extensions = v3_ca # The extensions to add to the self signed cert + +# Passwords for private keys if not present they will be prompted for +# input_password = secret +# output_password = secret + +# This sets a mask for permitted string types. There are several options. +# default: PrintableString, T61String, BMPString. +# pkix : PrintableString, BMPString (PKIX recommendation before 2004) +# utf8only: only UTF8Strings (PKIX recommendation after 2004). +# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings). +# MASK:XXXX a literal mask value. +# WARNING: ancient versions of Netscape crash on BMPStrings or UTF8Strings. +string_mask = utf8only + +# req_extensions = v3_req # The extensions to add to a certificate request + +[ req_distinguished_name ] +countryName = Country Name (2 letter code) +countryName_default = AU +countryName_min = 2 +countryName_max = 2 + +stateOrProvinceName = State or Province Name (full name) +stateOrProvinceName_default = Some-State + +localityName = Locality Name (eg, city) + +0.organizationName = Organization Name (eg, company) +0.organizationName_default = Internet Widgits Pty Ltd + +# we can do this but it is not needed normally :-) +#1.organizationName = Second Organization Name (eg, company) +#1.organizationName_default = World Wide Web Pty Ltd + +organizationalUnitName = Organizational Unit Name (eg, section) +#organizationalUnitName_default = + +commonName = Common Name (e.g. server FQDN or YOUR name) +commonName_max = 64 + +emailAddress = Email Address +emailAddress_max = 64 + +# SET-ex3 = SET extension number 3 + +[ req_attributes ] +challengePassword = A challenge password +challengePassword_min = 4 +challengePassword_max = 20 + +unstructuredName = An optional company name + +[ usr_cert ] + +# These extensions are added when 'ca' signs a request. + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE + +# This is typical in keyUsage for a client certificate. +# keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer + +# This stuff is for subjectAltName and issuerAltname. +# Import the email address. +# subjectAltName=email:copy +# An alternative to produce certificates that aren't +# deprecated according to PKIX. +# subjectAltName=email:move + +# Copy subject details +# issuerAltName=issuer:copy + +# This is required for TSA certificates. +# extendedKeyUsage = critical,timeStamping + +[ v3_req ] + +# Extensions to add to a certificate request + +basicConstraints = CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +[ v3_ca ] + + +# Extensions for a typical CA + + +# PKIX recommendation. + +subjectKeyIdentifier=hash + +authorityKeyIdentifier=keyid:always,issuer + +basicConstraints = critical,CA:true + +# Key usage: this is typical for a CA certificate. However since it will +# prevent it being used as an test self-signed certificate it is best +# left out by default. +# keyUsage = cRLSign, keyCertSign + +# Include email address in subject alt name: another PKIX recommendation +# subjectAltName=email:copy +# Copy issuer details +# issuerAltName=issuer:copy + +# DER hex encoding of an extension: beware experts only! +# obj=DER:02:03 +# Where 'obj' is a standard or added object +# You can even override a supported extension: +# basicConstraints= critical, DER:30:03:01:01:FF + +[ crl_ext ] + +# CRL extensions. +# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL. + +# issuerAltName=issuer:copy +authorityKeyIdentifier=keyid:always + +[ proxy_cert_ext ] +# These extensions should be added when creating a proxy certificate + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE + +# This is typical in keyUsage for a client certificate. +# keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer + +# This stuff is for subjectAltName and issuerAltname. +# Import the email address. +# subjectAltName=email:copy +# An alternative to produce certificates that aren't +# deprecated according to PKIX. +# subjectAltName=email:move + +# Copy subject details +# issuerAltName=issuer:copy + +# This really needs to be in place for it to be a proxy certificate. +proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo + +#################################################################### +[ tsa ] + +default_tsa = tsa_config1 # the default TSA section + +[ tsa_config1 ] + +# These are used by the TSA reply generation only. +dir = ./demoCA # TSA root directory +serial = $dir/tsaserial # The current serial number (mandatory) +crypto_device = builtin # OpenSSL engine to use for signing +signer_cert = $dir/tsacert.pem # The TSA signing certificate + # (optional) +certs = $dir/cacert.pem # Certificate chain to include in reply + # (optional) +signer_key = $dir/private/tsakey.pem # The TSA private key (optional) +signer_digest = sha256 # Signing digest to use. (Optional) +default_policy = tsa_policy1 # Policy if request did not specify it + # (optional) +other_policies = tsa_policy2, tsa_policy3 # acceptable policies (optional) +digests = sha1, sha256, sha384, sha512 # Acceptable message digests (mandatory) +accuracy = secs:1, millisecs:500, microsecs:100 # (optional) +clock_precision_digits = 0 # number of digits after dot. (optional) +ordering = yes # Is ordering defined for timestamps? + # (optional, default: no) +tsa_name = yes # Must the TSA name be included in the reply? + # (optional, default: no) +ess_cert_id_chain = no # Must the ESS cert id chain be included? + # (optional, default: no) +ess_cert_id_alg = sha1 # algorithm to compute certificate + # identifier (optional, default: sha1) + +[insta] # CMP using Insta Demo CA +# Message transfer +server = pki.certificate.fi:8700 +# proxy = # set this as far as needed, e.g., http://192.168.1.1:8080 +# tls_use = 0 +path = pkix/ + +# Server authentication +recipient = "/C=FI/O=Insta Demo/CN=Insta Demo CA" # or set srvcert or issuer +ignore_keyusage = 1 # potentially needed quirk +unprotected_errors = 1 # potentially needed quirk +extracertsout = insta.extracerts.pem + +# Client authentication +ref = 3078 # user identification +secret = pass:insta # can be used for both client and server side + +# Generic message options +cmd = ir # default operation, can be overridden on cmd line with, e.g., kur + +# Certificate enrollment +subject = "/CN=openssl-cmp-test" +newkey = insta.priv.pem +out_trusted = insta.ca.crt +certout = insta.cert.pem + +[pbm] # Password-based protection for Insta CA +# Server and client authentication +ref = $insta::ref # 3078 +secret = $insta::secret # pass:insta + +[signature] # Signature-based protection for Insta CA +# Server authentication +trusted = insta.ca.crt # does not include keyUsage digitalSignature + +# Client authentication +secret = # disable PBM +key = $insta::newkey # insta.priv.pem +cert = $insta::certout # insta.cert.pem + +[ir] +cmd = ir + +[cr] +cmd = cr + +[kur] +# Certificate update +cmd = kur +oldcert = $insta::certout # insta.cert.pem + +[rr] +# Certificate revocation +cmd = rr +oldcert = $insta::certout # insta.cert.pem \ No newline at end of file diff --git a/openssl.cnf b/openssl.cnf index ccd1225..6eb948a 100644 --- a/openssl.cnf +++ b/openssl.cnf @@ -1,57 +1,13 @@ -# -# OpenSSL example configuration file. -# See doc/man5/config.pod for more info. -# -# This is mostly being used for generation of certificate requests, -# but may be used for auto loading of providers - -# Note that you can include other files from the main configuration -# file using the .include directive. -#.include filename - -# This definition stops the following lines choking if HOME isn't -# defined. -HOME = . - -# Use this in order to automatically load providers. +# Activates the OpenSSL FIPS provider and makes FIPS the default for every +# algorithm fetch. The 'default' provider is deliberately left out, so that a +# non-approved algorithm fails instead of being served from outside the module. +# fipsmodule.cnf carries the module integrity MAC and is generated at build time. openssl_conf = openssl_init - -# For NodeJS nodejs_conf = nodejs_init -# Comment out the next line to ignore configuration errors config_diagnostics = 1 -# Extra OBJECT IDENTIFIER info: -# oid_file = $ENV::HOME/.oid -oid_section = new_oids - -# To use this configuration file with the "-extfile" option of the -# "openssl x509" utility, name here the section containing the -# X.509v3 extensions to use: -# extensions = -# (Alternatively, use a configuration file that has only -# X.509v3 extensions in its main [= default] section.) - -[ new_oids ] -# We can add new OIDs in here for use by 'ca', 'req' and 'ts'. -# Add a simple OID like this: -# testoid1=1.2.3.4 -# Or use config file substitution like this: -# testoid2=${testoid1}.5.6 - -# Policies used by the TSA examples. -tsa_policy1 = 1.2.3.4.1 -tsa_policy2 = 1.2.3.4.5.6 -tsa_policy3 = 1.2.3.4.5.7 - -# For FIPS -# Optionally include a file that is generated by the OpenSSL fipsinstall -# application. This file contains configuration data required by the OpenSSL -# fips provider. It contains a named section e.g. [fips_sect] which is -# referenced from the [provider_sect] below. -# Refer to the OpenSSL security policy for more information. -.include /usr/local/ssl/fipsmodule.cnf +.include /etc/ssl/fipsmodule.cnf [openssl_init] providers = provider_sect @@ -69,321 +25,3 @@ activate = 1 [algorithm_sect] default_properties = fips=yes - - -#################################################################### -[ ca ] -default_ca = CA_default # The default ca section - -#################################################################### -[ CA_default ] - -dir = ./demoCA # Where everything is kept -certs = $dir/certs # Where the issued certs are kept -crl_dir = $dir/crl # Where the issued crl are kept -database = $dir/index.txt # database index file. -#unique_subject = no # Set to 'no' to allow creation of - # several certs with same subject. -new_certs_dir = $dir/newcerts # default place for new certs. - -certificate = $dir/cacert.pem # The CA certificate -serial = $dir/serial # The current serial number -crlnumber = $dir/crlnumber # the current crl number - # must be commented out to leave a V1 CRL -crl = $dir/crl.pem # The current CRL -private_key = $dir/private/cakey.pem# The private key - -x509_extensions = usr_cert # The extensions to add to the cert - -# Comment out the following two lines for the "traditional" -# (and highly broken) format. -name_opt = ca_default # Subject Name options -cert_opt = ca_default # Certificate field options - -# Extension copying option: use with caution. -# copy_extensions = copy - -# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs -# so this is commented out by default to leave a V1 CRL. -# crlnumber must also be commented out to leave a V1 CRL. -# crl_extensions = crl_ext - -default_days = 365 # how long to certify for -default_crl_days= 30 # how long before next CRL -default_md = default # use public key default MD -preserve = no # keep passed DN ordering - -# A few difference way of specifying how similar the request should look -# For type CA, the listed attributes must be the same, and the optional -# and supplied fields are just that :-) -policy = policy_match - -# For the CA policy -[ policy_match ] -countryName = match -stateOrProvinceName = match -organizationName = match -organizationalUnitName = optional -commonName = supplied -emailAddress = optional - -# For the 'anything' policy -# At this point in time, you must list all acceptable 'object' -# types. -[ policy_anything ] -countryName = optional -stateOrProvinceName = optional -localityName = optional -organizationName = optional -organizationalUnitName = optional -commonName = supplied -emailAddress = optional - -#################################################################### -[ req ] -default_bits = 2048 -default_keyfile = privkey.pem -distinguished_name = req_distinguished_name -attributes = req_attributes -x509_extensions = v3_ca # The extensions to add to the self signed cert - -# Passwords for private keys if not present they will be prompted for -# input_password = secret -# output_password = secret - -# This sets a mask for permitted string types. There are several options. -# default: PrintableString, T61String, BMPString. -# pkix : PrintableString, BMPString (PKIX recommendation before 2004) -# utf8only: only UTF8Strings (PKIX recommendation after 2004). -# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings). -# MASK:XXXX a literal mask value. -# WARNING: ancient versions of Netscape crash on BMPStrings or UTF8Strings. -string_mask = utf8only - -# req_extensions = v3_req # The extensions to add to a certificate request - -[ req_distinguished_name ] -countryName = Country Name (2 letter code) -countryName_default = AU -countryName_min = 2 -countryName_max = 2 - -stateOrProvinceName = State or Province Name (full name) -stateOrProvinceName_default = Some-State - -localityName = Locality Name (eg, city) - -0.organizationName = Organization Name (eg, company) -0.organizationName_default = Internet Widgits Pty Ltd - -# we can do this but it is not needed normally :-) -#1.organizationName = Second Organization Name (eg, company) -#1.organizationName_default = World Wide Web Pty Ltd - -organizationalUnitName = Organizational Unit Name (eg, section) -#organizationalUnitName_default = - -commonName = Common Name (e.g. server FQDN or YOUR name) -commonName_max = 64 - -emailAddress = Email Address -emailAddress_max = 64 - -# SET-ex3 = SET extension number 3 - -[ req_attributes ] -challengePassword = A challenge password -challengePassword_min = 4 -challengePassword_max = 20 - -unstructuredName = An optional company name - -[ usr_cert ] - -# These extensions are added when 'ca' signs a request. - -# This goes against PKIX guidelines but some CAs do it and some software -# requires this to avoid interpreting an end user certificate as a CA. - -basicConstraints=CA:FALSE - -# This is typical in keyUsage for a client certificate. -# keyUsage = nonRepudiation, digitalSignature, keyEncipherment - -# PKIX recommendations harmless if included in all certificates. -subjectKeyIdentifier=hash -authorityKeyIdentifier=keyid,issuer - -# This stuff is for subjectAltName and issuerAltname. -# Import the email address. -# subjectAltName=email:copy -# An alternative to produce certificates that aren't -# deprecated according to PKIX. -# subjectAltName=email:move - -# Copy subject details -# issuerAltName=issuer:copy - -# This is required for TSA certificates. -# extendedKeyUsage = critical,timeStamping - -[ v3_req ] - -# Extensions to add to a certificate request - -basicConstraints = CA:FALSE -keyUsage = nonRepudiation, digitalSignature, keyEncipherment - -[ v3_ca ] - - -# Extensions for a typical CA - - -# PKIX recommendation. - -subjectKeyIdentifier=hash - -authorityKeyIdentifier=keyid:always,issuer - -basicConstraints = critical,CA:true - -# Key usage: this is typical for a CA certificate. However since it will -# prevent it being used as an test self-signed certificate it is best -# left out by default. -# keyUsage = cRLSign, keyCertSign - -# Include email address in subject alt name: another PKIX recommendation -# subjectAltName=email:copy -# Copy issuer details -# issuerAltName=issuer:copy - -# DER hex encoding of an extension: beware experts only! -# obj=DER:02:03 -# Where 'obj' is a standard or added object -# You can even override a supported extension: -# basicConstraints= critical, DER:30:03:01:01:FF - -[ crl_ext ] - -# CRL extensions. -# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL. - -# issuerAltName=issuer:copy -authorityKeyIdentifier=keyid:always - -[ proxy_cert_ext ] -# These extensions should be added when creating a proxy certificate - -# This goes against PKIX guidelines but some CAs do it and some software -# requires this to avoid interpreting an end user certificate as a CA. - -basicConstraints=CA:FALSE - -# This is typical in keyUsage for a client certificate. -# keyUsage = nonRepudiation, digitalSignature, keyEncipherment - -# PKIX recommendations harmless if included in all certificates. -subjectKeyIdentifier=hash -authorityKeyIdentifier=keyid,issuer - -# This stuff is for subjectAltName and issuerAltname. -# Import the email address. -# subjectAltName=email:copy -# An alternative to produce certificates that aren't -# deprecated according to PKIX. -# subjectAltName=email:move - -# Copy subject details -# issuerAltName=issuer:copy - -# This really needs to be in place for it to be a proxy certificate. -proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo - -#################################################################### -[ tsa ] - -default_tsa = tsa_config1 # the default TSA section - -[ tsa_config1 ] - -# These are used by the TSA reply generation only. -dir = ./demoCA # TSA root directory -serial = $dir/tsaserial # The current serial number (mandatory) -crypto_device = builtin # OpenSSL engine to use for signing -signer_cert = $dir/tsacert.pem # The TSA signing certificate - # (optional) -certs = $dir/cacert.pem # Certificate chain to include in reply - # (optional) -signer_key = $dir/private/tsakey.pem # The TSA private key (optional) -signer_digest = sha256 # Signing digest to use. (Optional) -default_policy = tsa_policy1 # Policy if request did not specify it - # (optional) -other_policies = tsa_policy2, tsa_policy3 # acceptable policies (optional) -digests = sha1, sha256, sha384, sha512 # Acceptable message digests (mandatory) -accuracy = secs:1, millisecs:500, microsecs:100 # (optional) -clock_precision_digits = 0 # number of digits after dot. (optional) -ordering = yes # Is ordering defined for timestamps? - # (optional, default: no) -tsa_name = yes # Must the TSA name be included in the reply? - # (optional, default: no) -ess_cert_id_chain = no # Must the ESS cert id chain be included? - # (optional, default: no) -ess_cert_id_alg = sha1 # algorithm to compute certificate - # identifier (optional, default: sha1) - -[insta] # CMP using Insta Demo CA -# Message transfer -server = pki.certificate.fi:8700 -# proxy = # set this as far as needed, e.g., http://192.168.1.1:8080 -# tls_use = 0 -path = pkix/ - -# Server authentication -recipient = "/C=FI/O=Insta Demo/CN=Insta Demo CA" # or set srvcert or issuer -ignore_keyusage = 1 # potentially needed quirk -unprotected_errors = 1 # potentially needed quirk -extracertsout = insta.extracerts.pem - -# Client authentication -ref = 3078 # user identification -secret = pass:insta # can be used for both client and server side - -# Generic message options -cmd = ir # default operation, can be overridden on cmd line with, e.g., kur - -# Certificate enrollment -subject = "/CN=openssl-cmp-test" -newkey = insta.priv.pem -out_trusted = insta.ca.crt -certout = insta.cert.pem - -[pbm] # Password-based protection for Insta CA -# Server and client authentication -ref = $insta::ref # 3078 -secret = $insta::secret # pass:insta - -[signature] # Signature-based protection for Insta CA -# Server authentication -trusted = insta.ca.crt # does not include keyUsage digitalSignature - -# Client authentication -secret = # disable PBM -key = $insta::newkey # insta.priv.pem -cert = $insta::certout # insta.cert.pem - -[ir] -cmd = ir - -[cr] -cmd = cr - -[kur] -# Certificate update -cmd = kur -oldcert = $insta::certout # insta.cert.pem - -[rr] -# Certificate revocation -cmd = rr -oldcert = $insta::certout # insta.cert.pem \ No newline at end of file diff --git a/renovate.json5 b/renovate.json5 index 5a12349..17feef6 100644 --- a/renovate.json5 +++ b/renovate.json5 @@ -1,70 +1,92 @@ -{ - "$schema": "https://docs.renovatebot.com/renovate-schema.json", - "extends": [ - ":semanticCommits", - "config:recommended", - "docker:enableMajor" - ], - "labels": [ - "dependencies", - "filigran team" - ], - "minimumReleaseAge": "3 days", - "prHourlyLimit": 2, - "prConcurrentLimit": 100, - "branchConcurrentLimit": 100, - "timezone": "Europe/Paris", - "schedule": [ - "* 0-4,22-23 * * 1-5", - "* * * * 0,6" - ], - "updateNotScheduled": false, - "rebaseWhen": "conflicted", - "automergeStrategy": "squash", - "customManagers": [ - { - "customType": "regex", - "managerFilePatterns": [ - "/Dockerfile*/" - ], - "matchStrings": [ - "ARG OPENSSL_VERSION=(?.*?)\\s" - ], - "datasourceTemplate": "github-tags", - "depNameTemplate": "openssl/openssl", - "extractVersionTemplate": "^openssl-(?.*)$", - "versioningTemplate": "semver" - }, - { - "customType": "regex", - "managerFilePatterns": [ - "/Dockerfile*/" - ], - "matchStrings": [ - "ARG PYTHON_VERSION=(?.*?)\\s" - ], - "datasourceTemplate": "github-tags", - "depNameTemplate": "python/cpython", - "extractVersionTemplate": "^v(?.*)$", - "versioningTemplate": "semver" - } - ], - "packageRules": [ - { - "matchPackageNames": [ - "openssl/openssl" - ], - "matchUpdateTypes": [ - "patch" - ], - "automerge": true - }, - { - "matchPackageNames": [ - "python/cpython" - ], - "allowedVersions": "<=3.12", - "automerge": true - } - ] -} +{ + $schema: 'https://docs.renovatebot.com/renovate-schema.json', + extends: [ + 'config:recommended', + 'docker:enableMajor', + ':semanticCommits', + ], + labels: [ + 'dependencies', + 'filigran team', + ], + minimumReleaseAge: '3 days', + // high limits so that all PRs are created at once during the schedule window rather than being drip-fed across multiple runs + prHourlyLimit: 100, + prConcurrentLimit: 100, + branchConcurrentLimit: 100, + timezone: 'Europe/Paris', + // weekdays outside working hours (22h-5h) + all weekend + schedule: [ + '* 0-4,22-23 * * 1-5', + '* * * * 0,6', + ], + // prevent Renovate from updating existing PRs outside the schedule window + updateNotScheduled: false, + // only rebase when there is a conflict; avoids unnecessary CI runs on every base branch change, can be removed when number of open PR is low + rebaseWhen: 'conflicted', + vulnerabilityAlerts: { + // as we don't rely on Renovate to be informed of dependency security advisories, + // vulnerabilityAlerts is disabled since it can cause problems by skipping minimumReleaseAge, schedule and other constraints + enabled: false, + }, + // The legacy images compile OpenSSL and CPython from pinned sources, so these + // pins are the only way they receive security fixes. Scoped to legacy/ on + // purpose: the root Dockerfile's PYTHON_VERSION is a tag assertion, not a + // source version, and must not be bumped by a bot. + customManagers: [ + { + customType: 'regex', + managerFilePatterns: ['/^legacy/Dockerfile/'], + matchStrings: ['ARG OPENSSL_VERSION=(?.*?)\\s'], + datasourceTemplate: 'github-tags', + depNameTemplate: 'openssl/openssl', + extractVersionTemplate: '^openssl-(?.*)$', + versioningTemplate: 'semver', + }, + { + customType: 'regex', + managerFilePatterns: ['/^legacy/Dockerfile/'], + matchStrings: ['ARG PYTHON_VERSION=(?.*?)\\s'], + datasourceTemplate: 'github-tags', + depNameTemplate: 'python/cpython', + extractVersionTemplate: '^v(?.*)$', + versioningTemplate: 'semver', + }, + ], + packageRules: [ + // group non-major devDependencies and GitHub Actions once a week to avoid Renovate noise + { + groupName: 'devDependencies (non-major)', + groupSlug: 'dev-dependencies-non-major', + description: 'Batch non-major updates of dev dependencies and GitHub Actions once a week on Sunday', + schedule: [ + '* * * * 0', + ], + matchDepTypes: [ + 'devDependencies', + 'action', + ], + matchUpdateTypes: [ + 'minor', + 'patch', + 'pin', + 'digest', + ], + // use 'auto' here so grouped PRs stay up-to-date automatically, + // since we batch them and want them merge-ready on Monday + rebaseWhen: 'auto', + }, + { + matchPackageNames: ['python/cpython'], + allowedVersions: '<=3.12', + }, + ], + // do lock file maintenance once a week on Sunday + lockFileMaintenance: { + schedule: [ + '* * * * 0', + ], + rebaseWhen: 'auto', + enabled: true, + }, +}