{"id":13818002,"url":"https://github.com/redhat-cop/cert-utils-operator","last_synced_at":"2025-04-09T22:02:40.685Z","repository":{"id":37768930,"uuid":"182403255","full_name":"redhat-cop/cert-utils-operator","owner":"redhat-cop","description":"Set of functionalities around certificates packaged in a Kubernetes operator","archived":false,"fork":false,"pushed_at":"2025-04-09T09:21:24.000Z","size":16232,"stargazers_count":99,"open_issues_count":38,"forks_count":34,"subscribers_count":17,"default_branch":"master","last_synced_at":"2025-04-09T22:02:33.414Z","etag":null,"topics":["container-cop","k8s-operator"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/redhat-cop.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-04-20T12:27:33.000Z","updated_at":"2025-03-07T18:47:09.000Z","dependencies_parsed_at":"2023-12-19T15:12:10.075Z","dependency_job_id":"8cab3021-27bb-486c-99dc-4d8f65464c1e","html_url":"https://github.com/redhat-cop/cert-utils-operator","commit_stats":null,"previous_names":[],"tags_count":30,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redhat-cop%2Fcert-utils-operator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redhat-cop%2Fcert-utils-operator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redhat-cop%2Fcert-utils-operator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redhat-cop%2Fcert-utils-operator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/redhat-cop","download_url":"https://codeload.github.com/redhat-cop/cert-utils-operator/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248119296,"owners_count":21050755,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["container-cop","k8s-operator"],"created_at":"2024-08-04T07:00:26.540Z","updated_at":"2025-04-09T22:02:40.652Z","avatar_url":"https://github.com/redhat-cop.png","language":"Go","funding_links":[],"categories":["Certificates Management"],"sub_categories":[],"readme":"# Cert-utils-operator\n\n![build status](https://github.com/redhat-cop/cert-utils-operator/workflows/push/badge.svg)\n[![Go Report Card](https://goreportcard.com/badge/github.com/redhat-cop/cert-utils-operator)](https://goreportcard.com/report/github.com/redhat-cop/cert-utils-operator)\n![GitHub go.mod Go version](https://img.shields.io/github/go-mod/go-version/redhat-cop/cert-utils-operator)\n\nCert utils operator is a set of functionalities around certificates packaged in a [Kubernetes operator](https://github.com/operator-framework/operator-sdk).\n\nCertificates are assumed to be available in a [secret](https://kubernetes.io/docs/concepts/configuration/secret/) of type `kubernetes.io/tls` (other types of secrets are *ignored* by this operator).\nBy convention this type of secrets have three optional entries:\n\n1. `tls.key`: the private key of the certificate.\n2. `tls.crt`: the actual certificate.\n3. `ca.crt`: the CA bundle that validates the certificate.\n\nThe functionalities are the following:\n\n1. [Ability to populate route certificates](#Populating-route-certificates)\n2. [Ability to create java keystore and truststore from the certificates](#Creating-java-keystore-and-truststore)\n3. [Ability to show info regarding the certificates](#Showing-info-on-the-certificates)\n4. [Ability to alert when a certificate is about to expire](#Alerting-when-a-certificate-is-about-to-expire)\n5. [Ability to inject ca bundles in Secrets, ConfigMaps, ValidatingWebhookConfiguration, MutatingWebhookConfiguration CustomResourceDefinition and APIService objects](#CA-injection)\n\nAll these feature are activated via opt-in annotations.\n\n## Populating route certificates\n\nThis feature works on [secure routes](https://docs.openshift.com/container-platform/3.11/architecture/networking/routes.html#secured-routes) with `edge` or `reencrypt` type of termination.\n\nThis feature is activated with the following annotation on a route: `cert-utils-operator.redhat-cop.io/certs-from-secret: \"\u003csecret-name\u003e\"`. Routes that are not secured (`tls.termination` field initialized to either `edge` or `reencrypt`) will be ignored even if they have the annotation.\n\nThe following fields of the route will be updated:\n\n1. `key` with the content of `tls.key`.\n2. `certificate` with the content of `tls.crt`.\n3. `caCertificate` with the content of `ca.crt`.\n\nIt is possible to control whether the `caCertificate` field should be injected via the following annotations `cert-utils-operator.redhat-cop.io/inject-CA: \"[true|false]\"`. The default is `true`. This can be useful if the certificate also contains the ca in ca.crt in its certificate chain. In this case the OpenShift route validation will fail.\n\nThe `destinationCACertificate` can also be injected. To activate this feature use the following annotation: `cert-utils-operator.redhat-cop.io/destinationCA-from-secret: \"\u003csecret-name\u003e\"`. The following field will be updated:\n\n1. `destinationCACertificate` with the content of `ca.crt`.\n\nNote that the two annotations can point to different secrets.\n\n## Creating java keystore and truststore\n\n### Secrets\n\nThis feature is activated with the following annotation on a `kubernetes.io/tls` secret: `cert-utils-operator.redhat-cop.io/generate-java-keystores: \"true\"`.\n\nWhen this annotation is set two more entries are added to the secret:\n\n1. `keystore.jks`: this Java keystore contains the `tls.crt` and `tls.key` certificate.\n2. `trustsstore.jks`: this Java keystore contains the `ca.crt` certificate.\n\nNote that Java Keystore require the key to be in [PKCS#8](https://en.wikipedia.org/wiki/PKCS_8) format. It is a responsibility of the certificate provisioner to make sure the key is in this format. No validation is currently performed by the cert-utils operator.\n\nA such annotated secret looks like the following:\n\n![keystore](media/keystore.png)\n\nThe default password for these keystores is `changeme`. The password can be changed by adding the following optional annotation: `cert-utils-operator.redhat-cop.io/java-keystore-password: \u003cpassword\u003e`. The alias of the certificate inside the keystore is `alias`.\n\n### ConfigMaps\n\nThis feature is activated with the following annotation on a configmap: `cert-utils-operator.redhat-cop.io/generate-java-truststore: \"true\"`.\n\nWhen this annotation is the following entry is added to the configmap as binaryData:\n\n1. `truststore.jks`: this Java keystore contains the `ca-bundle.crt` certificate.\n\nNote that Java Keystore require the key to be in [PKCS#8](https://en.wikipedia.org/wiki/PKCS_8) format. It is a responsibility of the certificate provisioner to make sure the key is in this format. No validation is currently performed by the cert-utils operator.\n\nThe default password for these keystores is `changeit`. The password can be changed by adding the following optional annotation: `cert-utils-operator.redhat-cop.io/java-keystore-password: \u003cpassword\u003e`. The alias of the certificate inside the keystore is `alias`.\n\n| Annotation  | Default  | Description  |\n|:-|:-:|---|\n| `cert-utils-operator.redhat-cop.io/java-keystore-password` | changeit | The password to use when consuming the JKS trust store |\n| `cert-utils-operator.redhat-cop.io/generate-java-truststore` | false | Should the JKS file be generated and attached to the configmap |\n| `cert-utils-operator.redhat-cop.io/source-ca-key` | ca-bundle.crt | The key in the configmap which will be read to generate the truststore.jks |\n\n## Showing info on the certificates\n\nThis feature is activated with the following annotation on a `kubernetes.io/tls` secret: `cert-utils-operator.redhat-cop.io/generate-cert-info: \"true\"`.\n\nWhen this annotation is set two more entries are added to the secret:\n\n1. `tls.crt.info`: this entries contains a textual representation of `tls.crt` the certificates in a similar notation to `openssl`.\n2. `ca.crt.info`: this entries contains a textual representation of `ca.crt` the certificates in a similar notation to `openssl`.\n\nA such annotated secret looks like the following:\n\n![certinfo](media/cert-info.png)\n\n## Alerting when a certificate is about to expire\n\nThis operator can generate Prometheus alerts and/or Kubernetes events when a certifciate is about to expire.\n\n### Generating prometheus alerts\n\nPrometheus alerts are generated for all certificates. In order for the certifciate metrics to be collected and the alerts be generated the Prometheus CRs deployed with this operator must be honored by a [Prometheus operator](https://github.com/prometheus-operator/prometheus-operator). If you are running on OpenShift just add the label ``openshift.io/cluster-monitoring=\"true\"`` to the namespace containing the operator.\n\nThe following metrics will be collected for every tls secret:\n\n| Metric Name | Description |\n|:-:|:-:|\n| `certutils_certificate_issue_time` | time at which the certificate was created in seconds from from January 1, 1970 UTC |\n| `certutils_certificate_expiry_time` | time at which the certificate expires in seconds from from January 1, 1970 UTC |\n| `cert:validity_duration:sec` | duration of the certificate validity in seconds |\n| `cert:time_to_expiration:sec` | time left to expiration in seconds |\n\nAlerts will be generated at 85% and 95% of the certifciate lifetime.\nAlerts are generated for all certificates including certifciate that are possibly automatically rotated. This is intentional as the automation that rotates the certificates may be non-functioning.\n\nIf these alerts are not useful in your deployment, you can be silenced them in alert-manager as described [here](https://prometheus.io/docs/alerting/latest/configuration/#inhibit_rule).\n\n### Generating Kubernetes events\n\nThis feature is activated with the following annotation on a `kubernetes.io/tls` secret: `cert-utils-operator.redhat-cop.io/generate-cert-expiry-alert: \"true\"`.\n\nWhen this annotation is set the secret will generate a Kubernetes `Warning` Event if the certificate is about to expire.\n\nThis feature is useful when the certificates are not renewed by an automatic system.\n\nThe timing of this alerting mechanism can be controller with the following annotations:\n\n| Annotation  | Default  | Description  |\n|:-|:-:|---|\n| `cert-utils-operator.redhat-cop.io/cert-expiry-check-frequency`  | 7 days  | with which frequency should the system check is a certificate is expiring  |\n| `cert-utils-operator.redhat-cop.io/cert-soon-to-expire-check-frequency`  | 1 hour  | with which frequency should the system check is a certificate is expired, once it's close to expiring  |\n| `cert-utils-operator.redhat-cop.io/cert-soon-to-expire-threshold`  | 90 days  | what is the interval of time below which we consider the certificate close to expiry  |\n\nHere is an example of a certificate soon-to-expiry event:\n\n![cert-expiry](media/cert-expiry.png)\n\n\n\n## CA Injection\n\n[ValidatingWebhookConfiguration](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/), [MutatingWebhokConfiguration](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/) [CustomResourceDefinition](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/) and [APIService](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/apiserver-aggregation/) types of objects (and possibly in the future others) need the master API process to connect to trusted servers to perform their function. In order to do so over an encrypted connection, a CA bundle needs to be configured. In these objects the CA bundle is passed as part of the CR and not as a secret, and that is fine because the CA bundles are public info. However it may be difficult at deploy time to know what the correct CA bundle should be. Often the CA bundle needs to be discovered as a piece on information owned by some other objects of the cluster.\n\nThis feature allows you to inject the ca bundle from either a `kubernetes.io/tls` secret or from the service_ca.crt file mounted in every pod. The latter is useful if you are protecting your webhook with a certificate generated with the [service service certificate secret](https://docs.openshift.com/container-platform/3.11/dev_guide/secrets.html#service-serving-certificate-secrets) feature.\n\nThis feature is activated by the following annotation:\n\n1. `cert-utils-operator.redhat-cop.io/injectca-from-secret: \u003csecret namespace\u003e/\u003csecret name\u003e`\n\nIn addition to those objects, it is also possible to inject ca bundles from secrets to secrets and configmaps:\n\n1. `secrets`: the secret must of type: `kubernetes.io/tls`. These types of secret must contain the `tls.crt` and `tls.key` keys, but is this case those keys are going to be presumably empty. So it is recommended to create these secrets as follows:\n  \n  ```yaml\n  apiVersion: v1\n  kind: Secret\n  metadata:\n    annotations:\n      cert-utils-operator.redhat-cop.io/injectca-from-secret: test-cert-utils/test1\n    name: test-inject-ca\n    namespace: test-cert-utils\n  type: kubernetes.io/tls\n  stringData:\n    tls.crt: \"\"\n    tls.key: \"\"\n  ```\n\n2. `confimaps`: the ca bundle will be injected in this key `ca.crt`, here is an example:\n\n  ```yaml\n  apiVersion: v1\n  kind: ConfigMap\n  metadata:\n    annotations:\n      cert-utils-operator.redhat-cop.io/injectca-from-secret: test-cert-utils/test1\n    name: test-inject-ca-cm\n    namespace: test-cert-utils\n  ```\n\n[Projected volumes](https://kubernetes.io/docs/concepts/storage/volumes/#projected) can be used to merge the caBundle with other pieces of configuration and or change the key name.\n\n## Metrics\n\nPrometheus compatible metrics are exposed by the Operator and can be integrated into OpenShift's default cluster monitoring. To enable OpenShift cluster monitoring, label the namespace the operator is deployed in with the label `openshift.io/cluster-monitoring=\"true\"`.\n\n```shell\noc label namespace \u003cnamespace\u003e openshift.io/cluster-monitoring=\"true\"\n```\n\n### Testing metrics\n\n```sh\nexport operatorNamespace=cert-utils-operator-local # or cert-utils-operator\noc label namespace ${operatorNamespace} openshift.io/cluster-monitoring=\"true\"\noc rsh -n openshift-monitoring -c prometheus prometheus-k8s-0 /bin/bash\nexport operatorNamespace=cert-utils-operator-local # or cert-utils-operator\ncurl -v -s -k -H \"Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)\" https://cert-utils-operator-controller-manager-metrics.${operatorNamespace}.svc.cluster.local:8443/metrics\nexit\n```\n\n## Deploying the Operator\n\nThis is a cluster-level operator that you can deploy in any namespace, `cert-utils-operator` is recommended.\n\nIt is recommended to deploy this operator via [`OperatorHub`](https://operatorhub.io/), but you can also deploy it using [`Helm`](https://helm.sh/).\n\n### Multiarch Support\n\n| Arch  | Support  |\n|:-:|:-:|\n| amd64  | ✅ |\n| arm64  | ✅  |\n| ppc64le  | ✅  |\n| s390x  | ✅  |\n\n### Deploying from OperatorHub\n\n\u003e **Note**: This operator supports being installed disconnected environments\n\nIf you want to utilize the Operator Lifecycle Manager (OLM) to install this operator, you can do so in two ways: from the UI or the CLI.\n\n#### Deploying from OperatorHub UI\n\n* If you would like to launch this operator from the UI, you'll need to navigate to the OperatorHub tab in the console. Before starting, make sure you've created the namespace that you want to install this operator to with the following:\n\n```shell\noc new-project cert-utils-operator\n```\n\n* Once there, you can search for this operator by name: `cert utils operator`. This will then return an item for our operator and you can select it to get started. Once you've arrived here, you'll be presented with an option to install, which will begin the process.\n* After clicking the install button, you can then select the namespace that you would like to install this to as well as the installation strategy you would like to proceed with (`Automatic` or `Manual`).\n* Once you've made your selection, you can select `Subscribe` and the installation will begin. After a few moments you can go ahead and check your namespace and you should see the operator running.\n\n![Cert Utils Operator](./media/cert-utils-operator.png)\n\n#### Deploying from OperatorHub using CLI\n\nIf you'd like to launch this operator from the command line, you can use the manifests contained in this repository by running the following:\n\noc new-project cert-utils-operator\n\n```shell\noc apply -f config/operatorhub -n cert-utils-operator\n```\n\nThis will create the appropriate OperatorGroup and Subscription and will trigger OLM to launch the operator in the specified namespace.\n\n### Deploying with Helm\n\nHere are the instructions to install the latest release with Helm.\n\n```shell\noc new-project cert-utils-operator\nhelm repo add cert-utils-operator https://redhat-cop.github.io/cert-utils-operator\nhelm repo update\nhelm install cert-utils-operator cert-utils-operator/cert-utils-operator\n```\n\nThis can later be updated with the following commands:\n\n```shell\nhelm repo update\nhelm upgrade cert-utils-operator cert-utils-operator/cert-utils-operator\n```\n\n## Development\n\n## Running the operator locally\n\n\u003e Note: this operator build process is tested with [podman](https://podman.io/), but some of the build files (Makefile specifically) use docker because they are generated automatically by operator-sdk. It is recommended [remap the docker command to the podman command](https://developers.redhat.com/blog/2020/11/19/transitioning-from-docker-to-podman#transition_to_the_podman_cli).\n\n```shell\nexport repo=raffaelespazzoli\ndocker login quay.io/$repo\noc new-project cert-utils-operator\noc project cert-utils-operator\noc label namespace cert-utils-operator openshift.io/cluster-monitoring=\"true\"\nenvsubst \u003c config/local-development/tilt/env-replace-image.yaml \u003e config/local-development/tilt/replace-image.yaml\ntilt up\n```\n\n### Test helm chart locally\n\nDefine an image and tag. For example...\n\n```shell\nexport imageRepository=\"quay.io/redhat-cop/cert-utils-operator\"\nexport imageTag=\"$(git -c 'versionsort.suffix=-' ls-remote --exit-code --refs --sort='version:refname' --tags https://github.com/redhat-cop/cert-utils-operator.git '*.*.*' | tail --lines=1 | cut --delimiter='/' --fields=3)\"\n```\n\nDeploy chart...\n\n```shell\nmake helmchart IMG=${imageRepository} VERSION=${imageTag}\nhelm upgrade -i cert-utils-operator-local charts/cert-utils-operator -n cert-utils-operator-local --create-namespace\n```\n\nDelete...\n\n```shell\nhelm delete cert-utils-operator-local -n cert-utils-operator-local\nkubectl delete -f charts/cert-utils-operator/crds/crds.yaml\n```\n\n## Building/Pushing the operator image\n\n```shell\nexport repo=raffaelespazzoli #replace with yours\ndocker login quay.io/$repo\nmake docker-build IMG=quay.io/$repo/cert-utils-operator:latest\nmake docker-push IMG=quay.io/$repo/cert-utils-operator:latest\n```\n\n## Deploy to OLM via bundle\n\n```shell\nmake manifests\nmake bundle IMG=quay.io/$repo/cert-utils-operator:latest\noperator-sdk bundle validate ./bundle --select-optional name=operatorhub\nmake bundle-build BUNDLE_IMG=quay.io/$repo/cert-utils-operator-bundle:latest\ndocker push quay.io/$repo/cert-utils-operator-bundle:latest\noperator-sdk bundle validate quay.io/$repo/cert-utils-operator-bundle:latest --select-optional name=operatorhub\noc new-project cert-utils-operator\noc label namespace cert-utils-operator openshift.io/cluster-monitoring=\"true\"\noperator-sdk cleanup cert-utils-operator -n cert-utils-operator\noperator-sdk run bundle --install-mode AllNamespaces -n cert-utils-operator quay.io/$repo/cert-utils-operator-bundle:latest\n```\n\n## Releasing\n\n```shell\ngit tag -a \"\u003ctagname\u003e\" -m \"\u003ccommit message\u003e\"\ngit push upstream \u003ctagname\u003e\n```\n\nIf you need to remove a release:\n\n```shell\ngit tag -d \u003ctagname\u003e\ngit push upstream --delete \u003ctagname\u003e\n```\n\nIf you need to \"move\" a release to the current main\n\n```shell\ngit tag -f \u003ctagname\u003e\ngit push upstream -f \u003ctagname\u003e\n```\n\n### Cleaning up\n\n```shell\noperator-sdk cleanup cert-utils-operator -n cert-utils-operator\noc delete operatorgroup operator-sdk-og\noc delete catalogsource cert-utils-operator-catalog\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fredhat-cop%2Fcert-utils-operator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fredhat-cop%2Fcert-utils-operator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fredhat-cop%2Fcert-utils-operator/lists"}