From a287530ea4fb238294a7fb0d8f8458e5d09e4550 Mon Sep 17 00:00:00 2001 From: Stacky McStackface Date: Mon, 24 Nov 2025 14:45:21 +0000 Subject: [PATCH] chore: Generated commit to update templated files since the last template run up to stackabletech/operator-templating@26d779fc312520d90a6698a380637cfac1f48d2e Reference-to: stackabletech/operator-templating@26d779f (chore: refactor pre-commit config and build workflow) --- .github/workflows/build.yml | 213 +--- .gitignore | 1 - .pre-commit-config.yaml | 23 + Makefile | 7 +- Tiltfile | 29 +- deploy/helm/secret-operator/crds/crds.yaml | 937 ++++++++++++++++++ .../secret-operator/templates/service.yaml | 6 +- scripts/run-tests | 2 - 8 files changed, 986 insertions(+), 232 deletions(-) create mode 100644 deploy/helm/secret-operator/crds/crds.yaml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ae1963e9..ceea33b8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -97,223 +97,12 @@ jobs: echo "skip_helm=true" >> "$GITHUB_OUTPUT" fi - run_cargodeny: - name: Run Cargo Deny - runs-on: ubuntu-latest - strategy: - matrix: - checks: - - advisories - - bans licenses sources - - # Prevent sudden announcement of a new advisory from failing ci: - continue-on-error: ${{ matrix.checks == 'advisories' }} - - steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - with: - persist-credentials: false - submodules: recursive - - uses: EmbarkStudios/cargo-deny-action@f2ba7abc2abebaf185c833c3961145a3c275caad # v2.0.13 - with: - command: check ${{ matrix.checks }} - - run_rustfmt: - name: Run Rustfmt - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - with: - persist-credentials: false - submodules: recursive - - uses: dtolnay/rust-toolchain@6d653acede28d24f02e3cd41383119e8b1b35921 - with: - toolchain: ${{ env.RUST_NIGHTLY_TOOLCHAIN_VERSION }} - components: rustfmt - - env: - RUST_TOOLCHAIN_VERSION: ${{ env.RUST_NIGHTLY_TOOLCHAIN_VERSION }} - run: cargo "+$RUST_TOOLCHAIN_VERSION" fmt --all -- --check - - run_clippy: - name: Run Clippy - runs-on: ubuntu-latest - steps: - - name: Install host dependencies - uses: awalsh128/cache-apt-pkgs-action@acb598e5ddbc6f68a970c5da0688d2f3a9f04d05 # v1.6.0 - with: - packages: protobuf-compiler krb5-user libkrb5-dev libclang-dev liblzma-dev libssl-dev pkg-config apt-transport-https - version: ubuntu-latest - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - with: - persist-credentials: false - submodules: recursive - - uses: dtolnay/rust-toolchain@6d653acede28d24f02e3cd41383119e8b1b35921 - with: - toolchain: ${{ env.RUST_TOOLCHAIN_VERSION }} - components: clippy - - uses: Swatinem/rust-cache@f13886b937689c021905a6b90929199931d60db1 # v2.8.1 - with: - key: clippy - cache-all-crates: "true" - # TODO (@Techassi): Remove this step (unmaintained action, kinda useless step anyway) - - name: Run clippy action to produce annotations - uses: giraffate/clippy-action@13b9d32482f25d29ead141b79e7e04e7900281e0 # v1.0.1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - if: env.GITHUB_TOKEN != null - with: - clippy_flags: --all-targets -- -D warnings - reporter: 'github-pr-review' - github_token: ${{ secrets.GITHUB_TOKEN }} - # TODO (@Techassi): Remove, done by pre-commit - - name: Run clippy manually without annotations - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - if: env.GITHUB_TOKEN == null - run: cargo clippy --color never -q --all-targets -- -D warnings - - # TODO (@Techassi): Can be done by pre-commit - run_rustdoc: - name: Run RustDoc - runs-on: ubuntu-latest - steps: - - name: Install host dependencies - uses: awalsh128/cache-apt-pkgs-action@acb598e5ddbc6f68a970c5da0688d2f3a9f04d05 # v1.6.0 - with: - packages: protobuf-compiler krb5-user libkrb5-dev libclang-dev liblzma-dev libssl-dev pkg-config apt-transport-https - version: ubuntu-latest - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - with: - submodules: recursive - - uses: dtolnay/rust-toolchain@6d653acede28d24f02e3cd41383119e8b1b35921 - with: - toolchain: ${{ env.RUST_TOOLCHAIN_VERSION }} - components: rustfmt - - uses: Swatinem/rust-cache@f13886b937689c021905a6b90929199931d60db1 # v2.8.1 - with: - key: doc - cache-all-crates: "true" - - run: cargo doc --document-private-items - - # TODO (@Techassi): Remove, done by pre-commit - run_tests: - name: Run Cargo Tests - runs-on: ubuntu-latest - steps: - - name: Install host dependencies - uses: awalsh128/cache-apt-pkgs-action@acb598e5ddbc6f68a970c5da0688d2f3a9f04d05 # v1.6.0 - with: - packages: protobuf-compiler krb5-user libkrb5-dev libclang-dev liblzma-dev libssl-dev pkg-config apt-transport-https - version: ubuntu-latest - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - with: - persist-credentials: false - submodules: recursive - - uses: dtolnay/rust-toolchain@6d653acede28d24f02e3cd41383119e8b1b35921 - with: - toolchain: ${{ env.RUST_TOOLCHAIN_VERSION }} - - uses: Swatinem/rust-cache@f13886b937689c021905a6b90929199931d60db1 # v2.8.1 - with: - key: test - cache-all-crates: "true" - - run: cargo test - - - # Similar to check_charts, this tries to render the README, and see if there are unintended changes. - # This will save us from merging changes to the wrong file (instead of the templated source), and from - # forgetting to render out modifications to the README. - check_readme: - name: Check if committed README is the one we would render from the available parts - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - with: - persist-credentials: false - submodules: recursive - - uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0 - with: - python-version: ${{ env.PYTHON_VERSION }} - - name: Install jinja2-cli - run: pip install jinja2-cli==0.8.2 - - name: Regenerate charts - run: make render-readme - - name: Check if committed README were up to date - run: git diff --exit-code - - name: Git Diff showed uncommitted changes - if: ${{ failure() }} - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 - with: - script: | - core.setFailed('Committed README are not up to date, please make sure to apply them to the templated partials, and re-commit!') - - # This job cleans up the CRDs and Helm charts, followed by rebuilding them - # It then runs a `git diff` and fails the entire workflow, if any difference is encountered. - # - # Since CRD files are generated during the 'cargo build' process we need to run this once after - # removing the CRD files to ensure that the checked in versions match what the code expects. - # - # The reason for this step is, that developers are expected to check in up-to-date versions of charts - # as we'd otherwise have to build these in CI and commit them back to the PR, which - # creates all kinds of problems. - # This failsafe simply aborts anything that has not had charts rebuilt before pushing. - check_charts: - name: Check if committed Helm charts are up to date - runs-on: ubuntu-latest - steps: - - name: Install host dependencies - uses: awalsh128/cache-apt-pkgs-action@acb598e5ddbc6f68a970c5da0688d2f3a9f04d05 # v1.6.0 - with: - packages: protobuf-compiler krb5-user libkrb5-dev libclang-dev liblzma-dev libssl-dev pkg-config apt-transport-https - version: ubuntu-latest - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - with: - persist-credentials: false - submodules: recursive - - name: Set up Helm - uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4 # v4.3.1 - with: - version: v3.16.1 - - name: Set up cargo - uses: dtolnay/rust-toolchain@6d653acede28d24f02e3cd41383119e8b1b35921 - with: - toolchain: ${{ env.RUST_TOOLCHAIN_VERSION }} - - uses: Swatinem/rust-cache@f13886b937689c021905a6b90929199931d60db1 # v2.8.1 - with: - key: charts - cache-all-crates: "true" - - name: Regenerate charts - run: make regenerate-charts - - name: Check if committed charts were up to date - run: git diff --exit-code - - name: Git Diff showed uncommitted changes - if: ${{ failure() }} - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 - with: - script: | - core.setFailed('Committed charts were not up to date, please regenerate and re-commit!') - - tests_passed: - name: All tests passed - needs: - - run_udeps - - run_cargodeny - - run_clippy - - run_rustfmt - - run_rustdoc - - run_tests - - check_charts - - check_readme - runs-on: ubuntu-latest - steps: - - name: log - run: echo All tests have passed! - # TODO (@Techassi): Most of these publishing and signing tasks can be done by our own actions. # Make use of them just like we do in docker-images. package_and_publish: name: Package Charts, Build Docker Image and publish them - ${{ matrix.runner }} needs: - - tests_passed + - run_udeps - check_helm_publish strategy: matrix: diff --git a/.gitignore b/.gitignore index abc7ff9a..2dbc7ab0 100644 --- a/.gitignore +++ b/.gitignore @@ -13,7 +13,6 @@ result image.tar tilt_options.json -local_values.yaml .direnv/ .direnvrc diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 60b6d59f..5461297f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -14,6 +14,13 @@ repos: args: ["--allow-missing-credentials"] - id: detect-private-key + - repo: https://github.com/EmbarkStudios/cargo-deny + # Failing to compile cargo-deny with version >0.18.3, needs rust 1.88.0 + rev: baa02b0a0c54e0578aae6bb7c7181ad00dc290af # 0.18.3 + hooks: + - id: cargo-deny + args: ["--all-features", "check", "advisories", "bans", "licenses", "sources"] + - repo: https://github.com/adrienverge/yamllint rev: 79a6b2b1392eaf49cdd32ac4f14be1a809bbd8f7 # 1.37.1 hooks: @@ -72,6 +79,22 @@ repos: pass_filenames: false files: Cargo\.lock + - id: check-readme + name: check-readme + language: system + entry: make render-readme + stages: [pre-commit, pre-merge-commit] + pass_filenames: false + files: .readme + + - id: cargo-doc + name: cargo-doc + language: system + entry: cargo doc --document-private-items + stages: [pre-commit, pre-merge-commit] + pass_filenames: false + files: \.rs$|Cargo\.(toml|lock) + - id: cargo-test name: cargo-test language: system diff --git a/Makefile b/Makefile index 9afd741a..96e1030d 100644 --- a/Makefile +++ b/Makefile @@ -105,6 +105,7 @@ compile-chart: version crds config chart-clean: rm -rf "deploy/helm/${OPERATOR_NAME}/configs" + rm -rf "deploy/helm/${OPERATOR_NAME}/crds" version: cat "deploy/helm/${OPERATOR_NAME}/Chart.yaml" | yq ".version = \"${VERSION}\" | .appVersion = \"${VERSION}\"" > "deploy/helm/${OPERATOR_NAME}/Chart.yaml.new" @@ -116,11 +117,9 @@ config: cp -r deploy/config-spec/* "deploy/helm/${OPERATOR_NAME}/configs";\ fi -# We generate a crds.yaml, so that the effect of code changes are visible. -# The operator will take care of the CRD rollout itself. crds: - mkdir -p extra - cargo run --bin stackable-"${OPERATOR_NAME}" -- crd > extra/crds.yaml + mkdir -p deploy/helm/"${OPERATOR_NAME}"/crds + cargo run --bin stackable-"${OPERATOR_NAME}" -- crd | yq eval '.metadata.annotations["helm.sh/resource-policy"]="keep"' - > "deploy/helm/${OPERATOR_NAME}/crds/crds.yaml" chart-lint: compile-chart docker run -it -v $(shell pwd):/build/helm-charts -w /build/helm-charts quay.io/helmpack/chart-testing:v3.5.0 ct lint --config deploy/helm/ct.yaml diff --git a/Tiltfile b/Tiltfile index 53c3a8e4..ee0941c3 100644 --- a/Tiltfile +++ b/Tiltfile @@ -17,6 +17,11 @@ custom_build( outputs_image_ref_to='result/ref', ) +# Load the latest CRDs from Nix +watch_file('result') +if os.path.exists('result'): + k8s_yaml('result/crds.yaml') + # We need to set the correct image annotation on the operator Deployment to use e.g. # oci.stackable.tech/sandbox/opa-operator:7y19m3d8clwxlv34v5q2x4p7v536s00g instead of # oci.stackable.tech/sandbox/opa-operator:0.0.0-dev (which does not exist) @@ -30,12 +35,18 @@ helm_values = settings.get('helm_values', None) helm_override_image_repository = 'image.repository=' + registry + '/' + operator_name -k8s_yaml(helm( - 'deploy/helm/' + operator_name, - name=operator_name, - namespace="stackable-operators", - set=[ - helm_override_image_repository, - ], - values=helm_values, -)) +# Exclude stale CRDs from Helm chart, and apply the rest +helm_crds, helm_non_crds = filter_yaml( + helm( + 'deploy/helm/' + operator_name, + name=operator_name, + namespace="stackable-operators", + set=[ + helm_override_image_repository, + ], + values=helm_values, + ), + api_version = "^apiextensions\\.k8s\\.io/.*$", + kind = "^CustomResourceDefinition$", +) +k8s_yaml(helm_non_crds) diff --git a/deploy/helm/secret-operator/crds/crds.yaml b/deploy/helm/secret-operator/crds/crds.yaml new file mode 100644 index 00000000..19c870e5 --- /dev/null +++ b/deploy/helm/secret-operator/crds/crds.yaml @@ -0,0 +1,937 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: secretclasses.secrets.stackable.tech + annotations: + helm.sh/resource-policy: keep +spec: + group: secrets.stackable.tech + names: + categories: [] + kind: SecretClass + plural: secretclasses + shortNames: [] + singular: secretclass + scope: Cluster + versions: + - additionalPrinterColumns: [] + name: v1alpha2 + schema: + openAPIV3Schema: + description: Auto-generated derived type for SecretClassSpec via `CustomResource` + properties: + spec: + description: |- + A [SecretClass](https://docs.stackable.tech/home/nightly/secret-operator/secretclass) is a cluster-global Kubernetes resource + that defines a category of secrets that the Secret Operator knows how to provision. + properties: + backend: + description: |- + Each SecretClass is associated with a single + [backend](https://docs.stackable.tech/home/nightly/secret-operator/secretclass#backend), + which dictates the mechanism for issuing that kind of Secret. + oneOf: + - required: + - k8sSearch + - required: + - autoTls + - required: + - certManager + - required: + - kerberosKeytab + properties: + autoTls: + description: |- + The [`autoTls` backend](https://docs.stackable.tech/home/nightly/secret-operator/secretclass#backend-autotls) + issues a TLS certificate signed by the Secret Operator. + The certificate authority can be provided by the administrator, or managed automatically by the Secret Operator. + + A new certificate and key pair will be generated and signed for each Pod, keys or certificates are never reused. + properties: + additionalTrustRoots: + default: [] + description: Additional trust roots which are added to the provided `ca.crt` file. + items: + oneOf: + - required: + - configMap + - required: + - secret + properties: + configMap: + description: |- + Reference (name and namespace) to a Kubernetes ConfigMap object where additional + certificates are stored. + The extensions of the keys denote its contents: A key suffixed with `.crt` contains a stack + of base64 encoded DER certificates, a key suffixed with `.der` contains a binary DER + certificate. + properties: + name: + description: Name of the ConfigMap being referred to. + type: string + namespace: + description: Namespace of the ConfigMap being referred to. + type: string + required: + - name + - namespace + type: object + secret: + description: |- + Reference (name and namespace) to a Kubernetes Secret object where additional certificates + are stored. + The extensions of the keys denote its contents: A key suffixed with `.crt` contains a stack + of base64 encoded DER certificates, a key suffixed with `.der` contains a binary DER + certificate. + properties: + name: + description: Name of the Secret being referred to. + type: string + namespace: + description: Namespace of the Secret being referred to. + type: string + required: + - name + - namespace + type: object + type: object + type: array + ca: + description: Configures the certificate authority used to issue Pod certificates. + properties: + autoGenerate: + default: false + description: |- + Whether the certificate authority should be managed by Secret Operator, including being generated + if it does not already exist. + type: boolean + caCertificateLifetime: + default: 365d + description: |- + The lifetime of each generated certificate authority. + + Should always be more than double `maxCertificateLifetime`. + + If `autoGenerate: true` then the Secret Operator will prepare a new CA certificate the old CA approaches expiration. + If `autoGenerate: false` then the Secret Operator will log a warning instead. + type: string + caCertificateRetirementDuration: + default: 1h + description: |- + Duration at the end of the CA certificate lifetime where no signed certificate will exist. + + Retired (or expired) CA certificates will not be published and will not be used for + signing leaf certificates. + type: string + keyGeneration: + default: + rsa: + length: 2048 + description: |- + The algorithm used to generate a key pair and required configuration settings. + Currently only RSA and a key length of 2048, 3072 or 4096 bits can be configured. + oneOf: + - required: + - rsa + properties: + rsa: + properties: + length: + description: |- + The amount of bits used for generating the RSA keypair. + Currently, `2048`, `3072` and `4096` are supported. Defaults to `2048` bits. + enum: + - 2048 + - 3072 + - 4096 + type: integer + required: + - length + type: object + type: object + secret: + description: |- + Reference (name and namespace) to a Kubernetes Secret object where the CA certificate + and key is stored in the keys `ca.crt` and `ca.key` respectively. + properties: + name: + description: Name of the Secret being referred to. + type: string + namespace: + description: Namespace of the Secret being referred to. + type: string + required: + - name + - namespace + type: object + required: + - secret + type: object + maxCertificateLifetime: + default: 15d + description: |- + Maximum lifetime the created certificates are allowed to have. + In case consumers request a longer lifetime than allowed by this setting, + the lifetime will be the minimum of both, so this setting takes precedence. + The default value is 15 days. + + The maximum lifetime must be less than a quarter of the active CA certificate lifetime + where the active CA certificate lifetime is `ca.ca_certificate_lifetime - + ca.ca_certificate_retirement_duration` to ensure that two subjects always have a common + CA certificate in their trust stores – assuming that CAs are rotated at half of their + active lifetimes. + + For instance, if a pod is created right before half of the active CA lifetime has + passed, then it is signed by this CA but it does not know yet the new CA certificate + which is created right afterwards. If another pod is created so that its certificate + lifetime ends right after the first active CA lifetime then it is signed by the new CA. + The `max_certificate_lifetime` must be chosen so that these two pods have no + overlapping lifetimes, otherwise the first pod would see the second one signed by an + unknown CA certificate. This can be achieved by the mentioned formula. + type: string + required: + - ca + type: object + certManager: + description: |- + The [`certManager` backend][1] injects a TLS certificate issued by [cert-manager]. + + A new certificate will be requested the first time it is used by a Pod, it + will be reused after that (subject to cert-manager renewal rules). + + [1]: https://docs.stackable.tech/home/nightly/secret-operator/secretclass#backend-certmanager + [cert-manager]: https://cert-manager.io/ + properties: + defaultCertificateLifetime: + default: 1d + description: |- + The default lifetime of certificates. + + Defaults to 1 day. This may need to be increased for external issuers that impose rate limits (such as Let's Encrypt). + type: string + issuer: + description: A reference to the cert-manager issuer that the certificates should be requested from. + properties: + kind: + description: |- + The kind of the issuer, Issuer or ClusterIssuer. + + If Issuer then it must be in the same namespace as the Pods using it. + enum: + - Issuer + - ClusterIssuer + type: string + name: + description: The name of the issuer. + type: string + required: + - kind + - name + type: object + keyGeneration: + default: + rsa: + length: 2048 + description: |- + The algorithm used to generate a key pair and required configuration settings. + Currently only RSA and a key length of 2048, 3072 or 4096 bits can be configured. + oneOf: + - required: + - rsa + properties: + rsa: + properties: + length: + description: |- + The amount of bits used for generating the RSA keypair. + Currently, `2048`, `3072` and `4096` are supported. Defaults to `2048` bits. + enum: + - 2048 + - 3072 + - 4096 + type: integer + required: + - length + type: object + type: object + required: + - issuer + type: object + k8sSearch: + description: |- + The [`k8sSearch` backend](https://docs.stackable.tech/home/nightly/secret-operator/secretclass#backend-k8ssearch) + can be used to mount Secrets across namespaces into Pods. + properties: + searchNamespace: + description: Configures the namespace searched for Secret objects. + oneOf: + - required: + - pod + - required: + - name + properties: + name: + description: |- + The Secret objects are located in a single global namespace. + Should be used for secrets that are provisioned by the cluster administrator. + type: string + pod: + description: |- + The Secret objects are located in the same namespace as the Pod object. + Should be used for Secrets that are provisioned by the application administrator. + type: object + type: object + trustStoreConfigMapName: + description: |- + Name of a ConfigMap that contains the information required to validate against this SecretClass. + + Resolved relative to `search_namespace`. + + Required to request a TrustStore for this SecretClass. + nullable: true + type: string + required: + - searchNamespace + type: object + kerberosKeytab: + description: |- + The [`kerberosKeytab` backend](https://docs.stackable.tech/home/nightly/secret-operator/secretclass#backend-kerberoskeytab) + creates a Kerberos keytab file for a selected realm. + The Kerberos KDC and administrator credentials must be provided by the administrator. + properties: + admin: + description: Kerberos admin configuration settings. + oneOf: + - required: + - mit + - required: + - activeDirectory + properties: + activeDirectory: + description: Credentials should be provisioned in a Microsoft Active Directory domain. + properties: + generateSamAccountName: + description: |- + Allows samAccountName generation for new accounts to be customized. + Note that setting this field (even if empty) makes the Secret Operator take + over the generation duty from the domain controller. + nullable: true + properties: + prefix: + default: '' + description: A prefix to be prepended to generated samAccountNames. + type: string + totalLength: + default: 20 + description: |- + The total length of generated samAccountNames, _including_ `prefix`. + Must be larger than the length of `prefix`, but at most `20`. + + Note that this should be as large as possible, to minimize the risk of collisions. + format: uint8 + maximum: 255.0 + minimum: 0.0 + type: integer + type: object + ldapServer: + description: |- + An AD LDAP server, such as the AD Domain Controller. + This must match the server’s FQDN, or GSSAPI authentication will fail. + type: string + ldapTlsCaSecret: + description: |- + Reference (name and namespace) to a Kubernetes Secret object containing + the TLS CA (in `ca.crt`) that the LDAP server’s certificate should be authenticated against. + properties: + name: + description: Name of the Secret being referred to. + type: string + namespace: + description: Namespace of the Secret being referred to. + type: string + required: + - name + - namespace + type: object + passwordCacheSecret: + description: |- + Reference (name and namespace) to a Kubernetes Secret object where workload + passwords will be stored. This must not be accessible to end users. + properties: + name: + description: Name of the Secret being referred to. + type: string + namespace: + description: Namespace of the Secret being referred to. + type: string + required: + - name + - namespace + type: object + schemaDistinguishedName: + description: |- + The root Distinguished Name (DN) for AD-managed schemas, + typically `CN=Schema,CN=Configuration,{domain_dn}`. + type: string + userDistinguishedName: + description: |- + The root Distinguished Name (DN) where service accounts should be provisioned, + typically `CN=Users,{domain_dn}`. + type: string + required: + - ldapServer + - ldapTlsCaSecret + - passwordCacheSecret + - schemaDistinguishedName + - userDistinguishedName + type: object + mit: + description: Credentials should be provisioned in a MIT Kerberos Admin Server. + properties: + kadminServer: + description: |- + The hostname of the Kerberos Admin Server. + This should be provided by the Kerberos administrator. + type: string + required: + - kadminServer + type: object + type: object + adminKeytabSecret: + description: |- + Reference (`name` and `namespace`) to a K8s Secret object where a + keytab with administrative privileges is stored in the key `keytab`. + properties: + name: + description: Name of the Secret being referred to. + type: string + namespace: + description: Namespace of the Secret being referred to. + type: string + required: + - name + - namespace + type: object + adminPrincipal: + description: The admin principal. + type: string + kdc: + description: |- + The hostname of the Kerberos Key Distribution Center (KDC). + This should be provided by the Kerberos administrator. + type: string + realmName: + description: The name of the Kerberos realm. This should be provided by the Kerberos administrator. + type: string + required: + - admin + - adminKeytabSecret + - adminPrincipal + - kdc + - realmName + type: object + type: object + required: + - backend + type: object + required: + - spec + title: SecretClass + type: object + served: true + storage: true + subresources: {} + - additionalPrinterColumns: [] + name: v1alpha1 + schema: + openAPIV3Schema: + description: Auto-generated derived type for SecretClassSpec via `CustomResource` + properties: + spec: + description: |- + A [SecretClass](https://docs.stackable.tech/home/nightly/secret-operator/secretclass) is a cluster-global Kubernetes resource + that defines a category of secrets that the Secret Operator knows how to provision. + properties: + backend: + description: |- + Each SecretClass is associated with a single + [backend](https://docs.stackable.tech/home/nightly/secret-operator/secretclass#backend), + which dictates the mechanism for issuing that kind of Secret. + oneOf: + - required: + - k8sSearch + - required: + - autoTls + - required: + - experimentalCertManager + - required: + - kerberosKeytab + properties: + autoTls: + description: |- + The [`autoTls` backend](https://docs.stackable.tech/home/nightly/secret-operator/secretclass#backend-autotls) + issues a TLS certificate signed by the Secret Operator. + The certificate authority can be provided by the administrator, or managed automatically by the Secret Operator. + + A new certificate and key pair will be generated and signed for each Pod, keys or certificates are never reused. + properties: + additionalTrustRoots: + default: [] + description: Additional trust roots which are added to the provided `ca.crt` file. + items: + oneOf: + - required: + - configMap + - required: + - secret + properties: + configMap: + description: |- + Reference (name and namespace) to a Kubernetes ConfigMap object where additional + certificates are stored. + The extensions of the keys denote its contents: A key suffixed with `.crt` contains a stack + of base64 encoded DER certificates, a key suffixed with `.der` contains a binary DER + certificate. + properties: + name: + description: Name of the ConfigMap being referred to. + type: string + namespace: + description: Namespace of the ConfigMap being referred to. + type: string + required: + - name + - namespace + type: object + secret: + description: |- + Reference (name and namespace) to a Kubernetes Secret object where additional certificates + are stored. + The extensions of the keys denote its contents: A key suffixed with `.crt` contains a stack + of base64 encoded DER certificates, a key suffixed with `.der` contains a binary DER + certificate. + properties: + name: + description: Name of the Secret being referred to. + type: string + namespace: + description: Namespace of the Secret being referred to. + type: string + required: + - name + - namespace + type: object + type: object + type: array + ca: + description: Configures the certificate authority used to issue Pod certificates. + properties: + autoGenerate: + default: false + description: |- + Whether the certificate authority should be managed by Secret Operator, including being generated + if it does not already exist. + type: boolean + caCertificateLifetime: + default: 365d + description: |- + The lifetime of each generated certificate authority. + + Should always be more than double `maxCertificateLifetime`. + + If `autoGenerate: true` then the Secret Operator will prepare a new CA certificate the old CA approaches expiration. + If `autoGenerate: false` then the Secret Operator will log a warning instead. + type: string + caCertificateRetirementDuration: + default: 1h + description: |- + Duration at the end of the CA certificate lifetime where no signed certificate will exist. + + Retired (or expired) CA certificates will not be published and will not be used for + signing leaf certificates. + type: string + keyGeneration: + default: + rsa: + length: 2048 + description: |- + The algorithm used to generate a key pair and required configuration settings. + Currently only RSA and a key length of 2048, 3072 or 4096 bits can be configured. + oneOf: + - required: + - rsa + properties: + rsa: + properties: + length: + description: |- + The amount of bits used for generating the RSA keypair. + Currently, `2048`, `3072` and `4096` are supported. Defaults to `2048` bits. + enum: + - 2048 + - 3072 + - 4096 + type: integer + required: + - length + type: object + type: object + secret: + description: |- + Reference (name and namespace) to a Kubernetes Secret object where the CA certificate + and key is stored in the keys `ca.crt` and `ca.key` respectively. + properties: + name: + description: Name of the Secret being referred to. + type: string + namespace: + description: Namespace of the Secret being referred to. + type: string + required: + - name + - namespace + type: object + required: + - secret + type: object + maxCertificateLifetime: + default: 15d + description: |- + Maximum lifetime the created certificates are allowed to have. + In case consumers request a longer lifetime than allowed by this setting, + the lifetime will be the minimum of both, so this setting takes precedence. + The default value is 15 days. + + The maximum lifetime must be less than a quarter of the active CA certificate lifetime + where the active CA certificate lifetime is `ca.ca_certificate_lifetime - + ca.ca_certificate_retirement_duration` to ensure that two subjects always have a common + CA certificate in their trust stores – assuming that CAs are rotated at half of their + active lifetimes. + + For instance, if a pod is created right before half of the active CA lifetime has + passed, then it is signed by this CA but it does not know yet the new CA certificate + which is created right afterwards. If another pod is created so that its certificate + lifetime ends right after the first active CA lifetime then it is signed by the new CA. + The `max_certificate_lifetime` must be chosen so that these two pods have no + overlapping lifetimes, otherwise the first pod would see the second one signed by an + unknown CA certificate. This can be achieved by the mentioned formula. + type: string + required: + - ca + type: object + experimentalCertManager: + description: |- + The [`certManager` backend][1] injects a TLS certificate issued by [cert-manager]. + + A new certificate will be requested the first time it is used by a Pod, it + will be reused after that (subject to cert-manager renewal rules). + + [1]: https://docs.stackable.tech/home/nightly/secret-operator/secretclass#backend-certmanager + [cert-manager]: https://cert-manager.io/ + properties: + defaultCertificateLifetime: + default: 1d + description: |- + The default lifetime of certificates. + + Defaults to 1 day. This may need to be increased for external issuers that impose rate limits (such as Let's Encrypt). + type: string + issuer: + description: A reference to the cert-manager issuer that the certificates should be requested from. + properties: + kind: + description: |- + The kind of the issuer, Issuer or ClusterIssuer. + + If Issuer then it must be in the same namespace as the Pods using it. + enum: + - Issuer + - ClusterIssuer + type: string + name: + description: The name of the issuer. + type: string + required: + - kind + - name + type: object + keyGeneration: + default: + rsa: + length: 2048 + description: |- + The algorithm used to generate a key pair and required configuration settings. + Currently only RSA and a key length of 2048, 3072 or 4096 bits can be configured. + oneOf: + - required: + - rsa + properties: + rsa: + properties: + length: + description: |- + The amount of bits used for generating the RSA keypair. + Currently, `2048`, `3072` and `4096` are supported. Defaults to `2048` bits. + enum: + - 2048 + - 3072 + - 4096 + type: integer + required: + - length + type: object + type: object + required: + - issuer + type: object + k8sSearch: + description: |- + The [`k8sSearch` backend](https://docs.stackable.tech/home/nightly/secret-operator/secretclass#backend-k8ssearch) + can be used to mount Secrets across namespaces into Pods. + properties: + searchNamespace: + description: Configures the namespace searched for Secret objects. + oneOf: + - required: + - pod + - required: + - name + properties: + name: + description: |- + The Secret objects are located in a single global namespace. + Should be used for secrets that are provisioned by the cluster administrator. + type: string + pod: + description: |- + The Secret objects are located in the same namespace as the Pod object. + Should be used for Secrets that are provisioned by the application administrator. + type: object + type: object + trustStoreConfigMapName: + description: |- + Name of a ConfigMap that contains the information required to validate against this SecretClass. + + Resolved relative to `search_namespace`. + + Required to request a TrustStore for this SecretClass. + nullable: true + type: string + required: + - searchNamespace + type: object + kerberosKeytab: + description: |- + The [`kerberosKeytab` backend](https://docs.stackable.tech/home/nightly/secret-operator/secretclass#backend-kerberoskeytab) + creates a Kerberos keytab file for a selected realm. + The Kerberos KDC and administrator credentials must be provided by the administrator. + properties: + admin: + description: Kerberos admin configuration settings. + oneOf: + - required: + - mit + - required: + - activeDirectory + properties: + activeDirectory: + description: Credentials should be provisioned in a Microsoft Active Directory domain. + properties: + experimentalGenerateSamAccountName: + description: |- + Allows samAccountName generation for new accounts to be customized. + Note that setting this field (even if empty) makes the Secret Operator take + over the generation duty from the domain controller. + nullable: true + properties: + prefix: + default: '' + description: A prefix to be prepended to generated samAccountNames. + type: string + totalLength: + default: 20 + description: |- + The total length of generated samAccountNames, _including_ `prefix`. + Must be larger than the length of `prefix`, but at most `20`. + + Note that this should be as large as possible, to minimize the risk of collisions. + format: uint8 + maximum: 255.0 + minimum: 0.0 + type: integer + type: object + ldapServer: + description: |- + An AD LDAP server, such as the AD Domain Controller. + This must match the server’s FQDN, or GSSAPI authentication will fail. + type: string + ldapTlsCaSecret: + description: |- + Reference (name and namespace) to a Kubernetes Secret object containing + the TLS CA (in `ca.crt`) that the LDAP server’s certificate should be authenticated against. + properties: + name: + description: Name of the Secret being referred to. + type: string + namespace: + description: Namespace of the Secret being referred to. + type: string + required: + - name + - namespace + type: object + passwordCacheSecret: + description: |- + Reference (name and namespace) to a Kubernetes Secret object where workload + passwords will be stored. This must not be accessible to end users. + properties: + name: + description: Name of the Secret being referred to. + type: string + namespace: + description: Namespace of the Secret being referred to. + type: string + required: + - name + - namespace + type: object + schemaDistinguishedName: + description: |- + The root Distinguished Name (DN) for AD-managed schemas, + typically `CN=Schema,CN=Configuration,{domain_dn}`. + type: string + userDistinguishedName: + description: |- + The root Distinguished Name (DN) where service accounts should be provisioned, + typically `CN=Users,{domain_dn}`. + type: string + required: + - ldapServer + - ldapTlsCaSecret + - passwordCacheSecret + - schemaDistinguishedName + - userDistinguishedName + type: object + mit: + description: Credentials should be provisioned in a MIT Kerberos Admin Server. + properties: + kadminServer: + description: |- + The hostname of the Kerberos Admin Server. + This should be provided by the Kerberos administrator. + type: string + required: + - kadminServer + type: object + type: object + adminKeytabSecret: + description: |- + Reference (`name` and `namespace`) to a K8s Secret object where a + keytab with administrative privileges is stored in the key `keytab`. + properties: + name: + description: Name of the Secret being referred to. + type: string + namespace: + description: Namespace of the Secret being referred to. + type: string + required: + - name + - namespace + type: object + adminPrincipal: + description: The admin principal. + type: string + kdc: + description: |- + The hostname of the Kerberos Key Distribution Center (KDC). + This should be provided by the Kerberos administrator. + type: string + realmName: + description: The name of the Kerberos realm. This should be provided by the Kerberos administrator. + type: string + required: + - admin + - adminKeytabSecret + - adminPrincipal + - kdc + - realmName + type: object + type: object + required: + - backend + type: object + required: + - spec + title: SecretClass + type: object + served: true + storage: false + subresources: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: truststores.secrets.stackable.tech + annotations: + helm.sh/resource-policy: keep +spec: + group: secrets.stackable.tech + names: + categories: [] + kind: TrustStore + plural: truststores + shortNames: [] + singular: truststore + scope: Namespaced + versions: + - additionalPrinterColumns: [] + name: v1alpha1 + schema: + openAPIV3Schema: + description: Auto-generated derived type for TrustStoreSpec via `CustomResource` + properties: + spec: + description: |- + A [TrustStore](https://docs.stackable.tech/home/nightly/secret-operator/truststore) requests information about how to + validate secrets issued by a [SecretClass](https://docs.stackable.tech/home/nightly/secret-operator/secretclass). + + The requested information is written to a ConfigMap with the same name as the TrustStore. + properties: + format: + description: The [format](https://docs.stackable.tech/home/nightly/secret-operator/secretclass#format) that the data should be converted into. + enum: + - tls-pem + - tls-pkcs12 + - kerberos + - null + nullable: true + type: string + secretClassName: + description: The name of the SecretClass that the request concerns. + type: string + targetKind: + default: ConfigMap + description: |- + Which Kubernetes kind should be used to output the requested information to. + + The trust information (such as a `ca.crt`) can be considered public information, so we put + it in a `ConfigMap` by default. However, some tools might require it to be placed in a + `Secret`, so we also support that. + + Can be either `ConfigMap` or `Secret`, defaults to `ConfigMap`. + enum: + - Secret + - ConfigMap + type: string + required: + - secretClassName + type: object + required: + - spec + title: TrustStore + type: object + served: true + storage: true + subresources: {} diff --git a/deploy/helm/secret-operator/templates/service.yaml b/deploy/helm/secret-operator/templates/service.yaml index 5cf6439b..0cb05696 100644 --- a/deploy/helm/secret-operator/templates/service.yaml +++ b/deploy/helm/secret-operator/templates/service.yaml @@ -1,4 +1,4 @@ -{{- if .Values.maintenance.customResourceDefinitions.maintain }} + --- apiVersion: v1 kind: Service @@ -11,11 +11,9 @@ metadata: {{- include "operator.labels" . | nindent 4 }} spec: selector: - webhook.stackable.tech/conversion: enabled - {{- include "operator.selectorLabels" . | nindent 4 }} + {{- include "operator.selectorLabels" . | nindent 6 }} ports: - name: conversion-webhook protocol: TCP port: 8443 targetPort: 8443 -{{- end }} diff --git a/scripts/run-tests b/scripts/run-tests index 7fa07fc5..00639f45 100755 --- a/scripts/run-tests +++ b/scripts/run-tests @@ -11,7 +11,6 @@ import shutil import subprocess import sys import tempfile -import time __version__ = "0.0.1" @@ -452,7 +451,6 @@ def main(argv) -> int: gen_tests(opts.test_suite, opts.namespace, opts.work_dir) with release_file(opts.operator, opts.skip_operator) as f: maybe_install_release(opts.skip_release, f, opts.listener_class_preset) - time.sleep(10) if opts.skip_tests: logging.info("Skip running tests.") else: