This Project aim to create a Kubernetes Operator that can aggregate many TLS Secret
into one single Opaque Secret
with many files.
It uses the "new" Kubernetes Custom Resource Definition API and is build using the Operator SDK Framework
- The user push Manifests to create some Certificates
- Cert-Manager is triggered and create to corresponding TLS Secrets
- CertMerge Operator watch for Secrets and is triggered when Cert-Manager create or update them
- CertMerge Operator also watch for CertMerge requests. In our case, we decided to merge ALL certificates with a Label certmerge=true into ONE SINGLE Opaque Secret. This is due to Istio limitation to only mount one secret inside the Ingress Gateway.
- CertMerge Operator create the Istio’s needed Secret
- the Istio Ingress Gateway watch for Gateway Resources. Each Gateway is defined to use a different certificate name (coming from the same single Secret which is mounted at start)
Read more detailed use in this Blog Post
Cert manager create a TLS Secret for each certificate you request Istio Ingress Gateway can only mount ONE secret for the SSL certificates
Using the certmerge-operator, we can use Cert-Manager to create many TLS Secrets and merge them into a single multi-file Secret that can be used by Istio Gateways.
You need to install many Manifests to setup the Operator.
For the moment it creates a cert-merge
Namespace and setup the operator inside.
You can then put the CertMerge
Manifests anywhere in the cluster.
You need Operator SDK CLI to be able to build. Follow the QuickStart to build it.
Then :
mkdir -p $GOPATH/src/github.com/prune998
cd $GOPATH/src/github.com/prune998
git clone https://github.com/prune998/certmerge-operator.git
cd certmerge-operator
operator-sdk generate k8s
operator-sdk build prune/certmerge-operator
docker push prune/certmerge-operator
As you obviously can't write to the Docker Hub Registry prune/certmerge-operator
, don't docker push
it :)
A docker image is available using Docker Hub Registry. Simply pull from there :
docker pull prune/certmerge-operator
You need a working Kubernetes Cluster and a configured kubectl
.
Use kubectl cluster-info
to ensure everything is fine prior to deploying the Operator.
The Operator is configured to deploy in certmerge-operator
Namespace and use a ClusterRole to give read access to Secret
resources.
kubectl apply -f deploy/namespace.yaml
kubectl -n cert-merge apply -f deploy/service_account.yaml
kubectl -n cert-merge apply -f deploy/role.yaml
kubectl -n cert-merge apply -f deploy/role_binding.yaml
kubectl -n cert-merge apply -f deploy/crds/certmerge_v1alpha1_certmerge_crd.yaml
kubectl -n cert-merge apply -f deploy/operator.yaml
You can install some secrets that will trigger the test Custom Resources. Secrets are installed in the Default Namespace for testing purpose :
kubectl -n default apply -f deploy/test_secrets
kubectl -n default apply -f deploy/test_cr
- namespaced secrets
For the moment the operator is able to merge any secret from any namespace. As data inside the CertMerge's Secrets is not namespaced, you could end with one secret overwriting another one with the same name from another namespace. The solution is to name each secret's data by<namespace>-<secret-name>.(key|crt)
. I still need to check the implication when using the certificate with Istio. - improve security
The Operator can read anySecret
in aNamespace
and merge it in anotherNamespace
. This is highly insecure and gives too much power over a sensible resource. - inform Istio (Envoy) when a file (a
Certificate
) inside a mergedSecret
is updated
apiVersion: certmerge.lecentre.net/v1alpha1
kind: CertMerge
metadata:
name: "test-certmerge-labels"
spec:
selector:
- labelselector:
matchLabels:
env: "dev"
certmerge: "true"
matchExpressions:
- key: certmanager.k8s.io/certificate-name
operator: exists
namespace: default
secretlist:
- name: test-ingressgateway-certs
namespace: default
- name: test-tls-secret
namespace: default
name: test-cert-merge
namespace: default
The selector is a list of LabelSelectors (matchLabels only). All labels are evaluated as a boolean AND. ex :
-
get all
dev
secrets that are managed bycertmerge
in namespacedefault
:selector: - labelselector: matchLabels: env: "dev" certmerge: "true" namespace: default
-
get all
dev
secrets that are managed bycertmerge
in namespacedefault
andprod
:selector: - labelselector: matchLabels: env: "dev" certmerge: "true" namespace: default - labelselector: matchLabels: env: "dev" certmerge: "true" namespace: prod
-
get all
dev
andprod
secrets that are managed bycertmerge
in namespacedefault
:selector: - labelselector: matchLabels: env: "dev" certmerge: "true" namespace: default - labelselector: matchLabels: env: "prod" certmerge: "true" namespace: default
-
get all secrets generated by
Cert-Manager
:selector: - labelselector: matchExpressions: - key: certmanager.k8s.io/certificate-name operator: exists
You can specify specific secrets to merge by listing them :
secretlist:
- name: test-secret-1
namespace: default
- name: test-secret-2
namespace: prod
The list of releases is the best place to look for information on changes between releases.
- 20190304
updated repo to support operatorhub
Dockerhub image name now
certmerge-operator