Skip to content

Instantly share code, notes, and snippets.

@amcginlay
Last active February 20, 2023 17:44
Show Gist options
  • Save amcginlay/c63f51a385bb7d785f35728f4d2cca85 to your computer and use it in GitHub Desktop.
Save amcginlay/c63f51a385bb7d785f35728f4d2cca85 to your computer and use it in GitHub Desktop.

Smallstep cert-manager issuer with TLSPK

Create KinD cluster, connect to TLSPK and deploy enterprise cert-manager

k8s_name=kind-$(date +"%y%m%d%H%M")
cat <<EOF | kind create cluster --config -
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
name: ${k8s_name}
nodes:
  - role: control-plane
EOF

k8s_name_tlspk=$(tr "-" "_" <<< ${k8s_name})
jsctl clusters connect ${k8s_name_tlspk}

jsctl operator deploy --auto-registry-credentials
sleep 2 && kubectl -n jetstack-secure wait --for=condition=Available=True --all deployments --timeout=-1s

sleep 5 && jsctl operator installations apply --auto-registry-credentials --cert-manager-replicas 1
sleep 2 && kubectl -n jetstack-secure wait --for=condition=Available=True --all deployments --timeout=-1s

Install the Smallstep CA and cert-manager issuer

helm repo add smallstep  https://smallstep.github.io/helm-charts && helm repo update
helm -n smallstep install step-certificates smallstep/step-certificates --create-namespace --wait
helm -n smallstep install step-issuer smallstep/step-issuer --create-namespace --wait

Enable Smallstep support in the approver-policy

The approver-policy component is mandated in TLSPK but, by default, it is only able to support issuers from the cert-manager.io and jetstack.io apiGroups. All external issuers are ignored since they fall outside this condition (e.g. certmanager.step.sm). This is a permissions issue which is raised here). In the meantime you can address this limitation with the following tactical fix.

Open the manifest, in whatever EDITOR you have configured, as follows.

kubectl edit clusterrole js-operator-approver-policy-permissions

... then add the following element to the list of rules:

rules:
- apiGroups:
  - certmanager.step.sm
  resourceNames:
  - stepissuers.certmanager.step.sm/*
  - stepclusterissuers.certmanager.step.sm/*
  resources:
  - signers
  verbs:
  - approve

Saving the file will apply those changes.

Create issuer object

ca_bundle=$(kubectl -n smallstep get configmaps/step-certificates-certs  -o jsonpath="{.data['root_ca\.crt']}" | base64 | tr -d \\n)
kid=$(kubectl -n smallstep get configmaps/step-certificates-config -o jsonpath="{.data['ca\.json']}"| jq '.authority.provisioners[0].key.kid' --raw-output)

cat << EOF | kubectl apply -f -
apiVersion: certmanager.step.sm/v1beta1
kind: StepClusterIssuer
metadata:
  name: step-issuer
spec:
  url: https://step-certificates.smallstep.svc.cluster.local
  caBundle: ${ca_bundle}
  provisioner:
    name: admin
    kid: ${kid}
    passwordRef:
      name: step-certificates-provisioner-password
      namespace: smallstep
      key: password
EOF

Create Certificate Request Policy

cat << EOF | kubectl apply -f -
apiVersion: policy.cert-manager.io/v1alpha1
kind: CertificateRequestPolicy
metadata:
  name: certificate-request-policy-smallstep
spec:
  allowed:
    commonName:
      value: '*'
    dnsNames:
      values:
      - '*'
  selector:
    issuerRef:
      group: certmanager.step.sm
      kind: StepClusterIssuer
      name: step-issuer
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: certificate-request-policy-smallstep:rbac
rules:
  - apiGroups: ["policy.cert-manager.io"]
    resources: ["certificaterequestpolicies"]
    verbs: ["use"]
    resourceNames: ["certificate-request-policy-smallstep"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: certificate-request-policy-tlspc:rbac
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: certificate-request-policy-smallstep:rbac
subjects:
- kind: Group
  name: system:authenticated
  apiGroup: rbac.authorization.k8s.io      
EOF

Create certificate

kubectl create namespace tests

cat << EOF | kubectl -n tests apply -f -
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: www.smallstep-demo.com
spec:
  secretName: www-smallstep-demo-com-tls
  commonName: www.smallstep-demo.com
  dnsNames:
    - www.smallstep-demo.com
  issuerRef:
    group: certmanager.step.sm
    kind: StepClusterIssuer
    name: step-issuer
EOF

Confirm certificate issuance

TODO need to confirm what is actually produced, since you get tls.key but no tls.crt in the secret. Also, the secretName: www-smallstep-demo-com-tls directive is not observed (secret name is suffixed with randon chars).

kubectl -n tests describe $(kubectl -n tests get secret -oname | head -1)

Terminate all

kind delete cluster --name ${k8s_name}
jsctl clusters delete ${k8s_name_tlspk} --force

Remember to mop up dangling service account for the cluster in TLSPK

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment