allow catalog-diff to compile catalogs on the puppet compilers (#462)

catalog-diff compiles a host's catalog in two environments and diffs them to validate puppet-prod changes before merge, which means compiling catalogs on behalf of other nodes via POST /puppet/v4/catalog. The compilers run the image default auth.conf, where that endpoint is denied.

- add a compiler auth.conf allowing catalog-diff.main.unkin.net to POST /puppet/v4/catalog
- add a pre-default entrypoint script seeding it into conf.d, failing hard if the source is absent
- mount both onto the compiler deployment via configMapGenerator

Reviewed-on: #462
Co-authored-by: unkin-agent <unkin-agent@unkin.net>
Co-committed-by: unkin-agent <unkin-agent@unkin.net>
This commit was merged in pull request #462.
This commit is contained in:
2026-09-12 16:31:08 +10:00
committed by BenVincent
parent 783a3db0fd
commit 55af4b2f16
4 changed files with 357 additions and 0 deletions
@@ -99,6 +99,12 @@ spec:
- mountPath: /docker-custom-entrypoint.d/post-startup/additional-ruby-gems.sh
name: additional-ruby-gems
subPath: additional-ruby-gems.sh
- mountPath: /configmaps/auth.conf
name: compiler-auth-conf
subPath: auth.conf
- mountPath: /docker-custom-entrypoint.d/pre-default/10-auth-conf.sh
name: compiler-auth-conf-seed
subPath: 10-auth-conf.sh
initContainers:
- name: copy-configmaps
image: busybox:1.35
@@ -234,5 +240,12 @@ spec:
configMap:
name: additional-ruby-gems
defaultMode: 0755
- name: compiler-auth-conf
configMap:
name: compiler-auth.conf
- name: compiler-auth-conf-seed
configMap:
name: compiler-auth-conf-seed
defaultMode: 0755
strategy:
type: RollingUpdate
+10
View File
@@ -54,6 +54,16 @@ configMapGenerator:
- resources/compiler/puppetdb.conf
options:
disableNameSuffixHash: true
- name: compiler-auth.conf
files:
- resources/compiler/auth.conf
options:
disableNameSuffixHash: true
- name: compiler-auth-conf-seed
files:
- resources/compiler/10-auth-conf.sh
options:
disableNameSuffixHash: true
- name: additional-ruby-gems
files:
- resources/additional-ruby-gems.sh
+14
View File
@@ -0,0 +1,14 @@
#!/bin/bash
set -euo pipefail
SRC=/configmaps/auth.conf
DST=/etc/puppetlabs/puppetserver/conf.d/auth.conf
# Copied rather than mounted: the entrypoint chowns conf.d and rewrites auth.conf,
# both of which fail on a read-only configmap mount and abort container startup.
if [ ! -s "$SRC" ]; then
echo "FATAL: $SRC missing or empty; refusing to start on the image default auth.conf" >&2
exit 1
fi
cp "$SRC" "$DST"
@@ -0,0 +1,320 @@
# Copied into conf.d at startup by 10-auth-conf.sh; the entrypoint then appends the
# admin API cache rule and re-renders the result, so the running file is not byte-identical.
authorization: {
version: 1
rules: [
{
# Allow nodes to retrieve their own catalog
match-request: {
path: "^/puppet/v3/catalog/([^/]+)$"
type: regex
method: [get, post]
}
allow: "$1"
sort-order: 500
name: "puppetlabs v3 catalog from agents"
},
{
# Allow catalog-diff to retrieve catalogs on behalf of others.
# sort-order 400 must stay lower than the puppetlabs deny that follows: rules
# sort by [sort-order, name] and the first match wins.
match-request: {
path: "^/puppet/v4/catalog/?$"
type: regex
method: post
}
allow: "catalog-diff.main.unkin.net"
sort-order: 400
name: "unkin v4 catalog for catalog-diff"
},
{
# Allow services to retrieve catalogs on behalf of others
match-request: {
path: "^/puppet/v4/catalog/?$"
type: regex
method: post
}
deny: "*"
sort-order: 500
name: "puppetlabs v4 catalog for services"
},
{
# Allow nodes to retrieve the certificate they requested earlier
match-request: {
path: "/puppet-ca/v1/certificate/"
type: path
method: get
}
allow-unauthenticated: true
sort-order: 500
name: "puppetlabs certificate"
},
{
# Allow all nodes to access the certificate revocation list
match-request: {
path: "/puppet-ca/v1/certificate_revocation_list/ca"
type: path
method: get
}
allow-unauthenticated: true
sort-order: 500
name: "puppetlabs crl"
},
{
# Allow nodes to request a new certificate
match-request: {
path: "/puppet-ca/v1/certificate_request"
type: path
method: [get, put]
}
allow-unauthenticated: true
sort-order: 500
name: "puppetlabs csr"
},
{
# Allow nodes to renew their certificate
match-request: {
path: "/puppet-ca/v1/certificate_renewal"
type: path
method: post
}
# this endpoint should never be unauthenticated, as it requires the cert to be provided.
allow: "*"
sort-order: 500
name: "puppetlabs certificate renewal"
},
{
# Allow the CA CLI to access the certificate_status endpoint
match-request: {
path: "/puppet-ca/v1/certificate_status"
type: path
method: [get, put, delete]
}
allow: {
extensions: {
pp_cli_auth: "true"
}
}
sort-order: 500
name: "puppetlabs cert status"
},
{
match-request: {
path: "^/puppet-ca/v1/certificate_revocation_list$"
type: regex
method: put
}
allow: {
extensions: {
pp_cli_auth: "true"
}
}
sort-order: 500
name: "puppetlabs CRL update"
},
{
# Allow the CA CLI to access the certificate_statuses endpoint
match-request: {
path: "/puppet-ca/v1/certificate_statuses"
type: path
method: get
}
allow: {
extensions: {
pp_cli_auth: "true"
}
}
sort-order: 500
name: "puppetlabs cert statuses"
},
{
# Allow authenticated access to the CA expirations endpoint
match-request: {
path: "/puppet-ca/v1/expirations"
type: path
method: get
}
allow: "*"
sort-order: 500
name: "puppetlabs CA cert and CRL expirations"
},
{
# Allow the CA CLI to access the certificate clean endpoint
match-request: {
path: "/puppet-ca/v1/clean"
type: path
method: put
}
allow: {
extensions: {
pp_cli_auth: "true"
}
}
sort-order: 500
name: "puppetlabs cert clean"
},
{
# Allow the CA CLI to access the certificate sign endpoint
match-request: {
path: "/puppet-ca/v1/sign"
type: path
method: post
}
allow: {
extensions: {
pp_cli_auth: "true"
}
}
sort-order: 500
name: "puppetlabs cert sign"
},
{
# Allow the CA CLI to access the certificate sign all endpoint
match-request: {
path: "/puppet-ca/v1/sign/all"
type: path
method: post
}
allow: {
extensions: {
pp_cli_auth: "true"
}
}
sort-order: 500
name: "puppetlabs cert sign all"
},
{
# Allow unauthenticated access to the status service endpoint
match-request: {
path: "/status/v1/services"
type: path
method: get
}
allow-unauthenticated: true
sort-order: 500
name: "puppetlabs status service - full"
},
{
match-request: {
path: "/status/v1/simple"
type: path
method: get
}
allow-unauthenticated: true
sort-order: 500
name: "puppetlabs status service - simple"
},
{
match-request: {
path: "/puppet/v3/environments"
type: path
method: get
}
allow: "*"
sort-order: 500
name: "puppetlabs environments"
},
{
# Allow nodes to access all file_bucket_files. Note that access for
# the 'delete' method is forbidden by Puppet regardless of the
# configuration of this rule.
match-request: {
path: "/puppet/v3/file_bucket_file"
type: path
method: [get, head, post, put]
}
allow: "*"
sort-order: 500
name: "puppetlabs file bucket file"
},
{
# Allow nodes to access all file_content. Note that access for the
# 'delete' method is forbidden by Puppet regardless of the
# configuration of this rule.
match-request: {
path: "/puppet/v3/file_content"
type: path
method: [get, post]
}
allow: "*"
sort-order: 500
name: "puppetlabs file content"
},
{
# Allow nodes to access all file_metadata. Note that access for the
# 'delete' method is forbidden by Puppet regardless of the
# configuration of this rule.
match-request: {
path: "/puppet/v3/file_metadata"
type: path
method: [get, post]
}
allow: "*"
sort-order: 500
name: "puppetlabs file metadata"
},
{
# Allow nodes to retrieve only their own node definition
match-request: {
path: "^/puppet/v3/node/([^/]+)$"
type: regex
method: get
}
allow: "$1"
sort-order: 500
name: "puppetlabs node"
},
{
# Allow nodes to store only their own reports
match-request: {
path: "^/puppet/v3/report/([^/]+)$"
type: regex
method: put
}
allow: "$1"
sort-order: 500
name: "puppetlabs report"
},
{
# Allow nodes to update their own facts
match-request: {
path: "^/puppet/v3/facts/([^/]+)$"
type: regex
method: put
}
allow: "$1"
sort-order: 500
name: "puppetlabs facts"
},
{
match-request: {
path: "/puppet/v3/static_file_content"
type: path
method: get
}
allow: "*"
sort-order: 500
name: "puppetlabs static file content"
},
{
match-request: {
path: "/puppet/v3/tasks"
type: path
}
allow: "*"
sort-order: 500
name: "puppet tasks information"
},
{
# Deny everything else. This ACL is not strictly
# necessary, but illustrates the default policy
match-request: {
path: "/"
type: path
}
deny: "*"
sort-order: 999
name: "puppetlabs deny all"
}
]
}