Files
toallab-automation/roles/sno_deploy/tasks/configure_certmanager.yml

543 lines
17 KiB
YAML

---
# Install cert-manager operator and configure LetsEncrypt certificates.
#
# Installs the Red Hat cert-manager operator via OLM, creates a ClusterIssuer
# for LetsEncrypt with DNS-01 challenges via DNS Made Easy, and provisions
# certificates for the ingress wildcard and API server.
# ------------------------------------------------------------------
# Step 1: Install cert-manager operator via OLM
# ------------------------------------------------------------------
- name: Ensure cert-manager-operator namespace exists
kubernetes.core.k8s:
state: present
definition:
apiVersion: v1
kind: Namespace
metadata:
name: cert-manager-operator
- name: Create OperatorGroup for cert-manager-operator
kubernetes.core.k8s:
state: present
definition:
apiVersion: operators.coreos.com/v1
kind: OperatorGroup
metadata:
name: cert-manager-operator
namespace: cert-manager-operator
spec:
targetNamespaces:
- cert-manager-operator
- name: Subscribe to cert-manager operator
kubernetes.core.k8s:
state: present
definition:
apiVersion: operators.coreos.com/v1alpha1
kind: Subscription
metadata:
name: openshift-cert-manager-operator
namespace: cert-manager-operator
spec:
channel: "{{ sno_deploy_certmanager_channel }}"
installPlanApproval: Automatic
name: openshift-cert-manager-operator
source: "{{ sno_deploy_certmanager_source }}"
sourceNamespace: openshift-marketplace
# ------------------------------------------------------------------
# Step 2: Wait for cert-manager to be ready
# ------------------------------------------------------------------
- name: Wait for cert-manager CRDs to be available
kubernetes.core.k8s_info:
api_version: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
name: certificates.cert-manager.io
register: __sno_deploy_certmanager_crd
until: __sno_deploy_certmanager_crd.resources | length > 0
retries: "{{ (sno_deploy_certmanager_wait_timeout / 10) | int }}"
delay: 10
- name: Wait for cert-manager deployment to be ready
kubernetes.core.k8s_info:
api_version: apps/v1
kind: Deployment
namespace: cert-manager
name: cert-manager
register: __sno_deploy_certmanager_deploy
until: >-
__sno_deploy_certmanager_deploy.resources | length > 0 and
(__sno_deploy_certmanager_deploy.resources[0].status.readyReplicas | default(0)) >= 1
retries: "{{ (sno_deploy_certmanager_wait_timeout / 10) | int }}"
delay: 10
# ------------------------------------------------------------------
# Step 3: Create DNS Made Easy API credentials for DNS-01 challenges
# ------------------------------------------------------------------
- name: Create DNS Made Easy API credentials secret
kubernetes.core.k8s:
state: present
definition:
apiVersion: v1
kind: Secret
metadata:
name: dme-api-credentials
namespace: cert-manager
type: Opaque
stringData:
api-key: "{{ dme_account_key }}"
secret-key: "{{ dme_account_secret }}"
no_log: true
# ------------------------------------------------------------------
# Step 4: Deploy DNS Made Easy webhook solver
# ------------------------------------------------------------------
- name: Create webhook namespace
kubernetes.core.k8s:
state: present
definition:
apiVersion: v1
kind: Namespace
metadata:
name: cert-manager-webhook-dnsmadeeasy
- name: Create webhook ServiceAccount
kubernetes.core.k8s:
state: present
definition:
apiVersion: v1
kind: ServiceAccount
metadata:
name: cert-manager-webhook-dnsmadeeasy
namespace: cert-manager-webhook-dnsmadeeasy
- name: Create webhook ClusterRole
kubernetes.core.k8s:
state: present
definition:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: cert-manager-webhook-dnsmadeeasy
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "list", "watch"]
- apiGroups: ["flowcontrol.apiserver.k8s.io"]
resources: ["flowschemas", "prioritylevelconfigurations"]
verbs: ["list", "watch"]
- name: Create webhook ClusterRoleBinding
kubernetes.core.k8s:
state: present
definition:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: cert-manager-webhook-dnsmadeeasy
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cert-manager-webhook-dnsmadeeasy
subjects:
- kind: ServiceAccount
name: cert-manager-webhook-dnsmadeeasy
namespace: cert-manager-webhook-dnsmadeeasy
- name: Create auth-delegator ClusterRoleBinding for webhook
kubernetes.core.k8s:
state: present
definition:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: cert-manager-webhook-dnsmadeeasy:auth-delegator
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:auth-delegator
subjects:
- kind: ServiceAccount
name: cert-manager-webhook-dnsmadeeasy
namespace: cert-manager-webhook-dnsmadeeasy
- name: Create authentication-reader RoleBinding for webhook
kubernetes.core.k8s:
state: present
definition:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: cert-manager-webhook-dnsmadeeasy:webhook-authentication-reader
namespace: kube-system
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: extension-apiserver-authentication-reader
subjects:
- kind: ServiceAccount
name: cert-manager-webhook-dnsmadeeasy
namespace: cert-manager-webhook-dnsmadeeasy
- name: Create domain-solver ClusterRole for cert-manager
kubernetes.core.k8s:
state: present
definition:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: cert-manager-webhook-dnsmadeeasy:domain-solver
rules:
- apiGroups: ["{{ sno_deploy_webhook_group_name }}"]
resources: ["*"]
verbs: ["create"]
- name: Bind domain-solver to cert-manager ServiceAccount
kubernetes.core.k8s:
state: present
definition:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: cert-manager-webhook-dnsmadeeasy:domain-solver
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cert-manager-webhook-dnsmadeeasy:domain-solver
subjects:
- kind: ServiceAccount
name: cert-manager
namespace: cert-manager
- name: Create self-signed Issuer for webhook TLS
kubernetes.core.k8s:
state: present
definition:
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: cert-manager-webhook-dnsmadeeasy-selfsign
namespace: cert-manager-webhook-dnsmadeeasy
spec:
selfSigned: {}
- name: Create webhook TLS certificate
kubernetes.core.k8s:
state: present
definition:
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: cert-manager-webhook-dnsmadeeasy-tls
namespace: cert-manager-webhook-dnsmadeeasy
spec:
secretName: cert-manager-webhook-dnsmadeeasy-tls
duration: 8760h
renewBefore: 720h
issuerRef:
name: cert-manager-webhook-dnsmadeeasy-selfsign
kind: Issuer
dnsNames:
- cert-manager-webhook-dnsmadeeasy
- cert-manager-webhook-dnsmadeeasy.cert-manager-webhook-dnsmadeeasy
- cert-manager-webhook-dnsmadeeasy.cert-manager-webhook-dnsmadeeasy.svc
- name: Deploy webhook solver
kubernetes.core.k8s:
state: present
definition:
apiVersion: apps/v1
kind: Deployment
metadata:
name: cert-manager-webhook-dnsmadeeasy
namespace: cert-manager-webhook-dnsmadeeasy
spec:
replicas: 1
selector:
matchLabels:
app: cert-manager-webhook-dnsmadeeasy
template:
metadata:
labels:
app: cert-manager-webhook-dnsmadeeasy
spec:
serviceAccountName: cert-manager-webhook-dnsmadeeasy
containers:
- name: webhook
image: "{{ sno_deploy_webhook_image }}"
args:
- --tls-cert-file=/tls/tls.crt
- --tls-private-key-file=/tls/tls.key
- --secure-port=8443
ports:
- containerPort: 8443
name: https
protocol: TCP
env:
- name: GROUP_NAME
value: "{{ sno_deploy_webhook_group_name }}"
livenessProbe:
httpGet:
path: /healthz
port: https
scheme: HTTPS
initialDelaySeconds: 5
periodSeconds: 10
readinessProbe:
httpGet:
path: /healthz
port: https
scheme: HTTPS
initialDelaySeconds: 5
periodSeconds: 10
resources:
requests:
cpu: 10m
memory: 32Mi
limits:
memory: 64Mi
volumeMounts:
- name: certs
mountPath: /tls
readOnly: true
volumes:
- name: certs
secret:
secretName: cert-manager-webhook-dnsmadeeasy-tls
- name: Create webhook Service
kubernetes.core.k8s:
state: present
definition:
apiVersion: v1
kind: Service
metadata:
name: cert-manager-webhook-dnsmadeeasy
namespace: cert-manager-webhook-dnsmadeeasy
spec:
type: ClusterIP
ports:
- port: 443
targetPort: https
protocol: TCP
name: https
selector:
app: cert-manager-webhook-dnsmadeeasy
- name: Register webhook APIService
kubernetes.core.k8s:
state: present
definition:
apiVersion: apiregistration.k8s.io/v1
kind: APIService
metadata:
name: "v1alpha1.{{ sno_deploy_webhook_group_name }}"
spec:
group: "{{ sno_deploy_webhook_group_name }}"
groupPriorityMinimum: 1000
versionPriority: 15
service:
name: cert-manager-webhook-dnsmadeeasy
namespace: cert-manager-webhook-dnsmadeeasy
version: v1alpha1
insecureSkipTLSVerify: true
- name: Wait for webhook deployment to be ready
kubernetes.core.k8s_info:
api_version: apps/v1
kind: Deployment
namespace: cert-manager-webhook-dnsmadeeasy
name: cert-manager-webhook-dnsmadeeasy
register: __sno_deploy_webhook_deploy
until: >-
__sno_deploy_webhook_deploy.resources | length > 0 and
(__sno_deploy_webhook_deploy.resources[0].status.readyReplicas | default(0)) >= 1
retries: 30
delay: 10
# ------------------------------------------------------------------
# Step 5: Create ClusterIssuer for LetsEncrypt
# ------------------------------------------------------------------
- name: Create LetsEncrypt ClusterIssuer
kubernetes.core.k8s:
state: present
definition:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-production
spec:
acme:
email: "{{ sno_deploy_letsencrypt_email }}"
server: "{{ __sno_deploy_letsencrypt_server_url }}"
privateKeySecretRef:
name: letsencrypt-production-account-key
solvers:
- dns01:
webhook:
groupName: "{{ sno_deploy_webhook_group_name }}"
solverName: dnsmadeeasy
config:
apiKeySecretRef:
name: dme-api-credentials
key: api-key
secretKeySecretRef:
name: dme-api-credentials
key: secret-key
- name: Wait for ClusterIssuer to be ready
kubernetes.core.k8s_info:
api_version: cert-manager.io/v1
kind: ClusterIssuer
name: letsencrypt-production
register: __sno_deploy_clusterissuer
until: >-
__sno_deploy_clusterissuer.resources | length > 0 and
(__sno_deploy_clusterissuer.resources[0].status.conditions | default([])
| selectattr('type', '==', 'Ready')
| selectattr('status', '==', 'True') | list | length > 0)
retries: 12
delay: 10
# ------------------------------------------------------------------
# Step 6: Create Certificate resources
# ------------------------------------------------------------------
- name: Create apps wildcard certificate
kubernetes.core.k8s:
state: present
definition:
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: apps-wildcard-cert
namespace: openshift-ingress
spec:
secretName: apps-wildcard-tls
issuerRef:
name: letsencrypt-production
kind: ClusterIssuer
dnsNames:
- "{{ __sno_deploy_apps_wildcard }}"
duration: 2160h
renewBefore: 720h
- name: Create API server certificate
kubernetes.core.k8s:
state: present
definition:
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: api-server-cert
namespace: openshift-config
spec:
secretName: api-server-tls
issuerRef:
name: letsencrypt-production
kind: ClusterIssuer
dnsNames:
- "{{ __sno_deploy_api_hostname }}"
duration: 2160h
renewBefore: 720h
# ------------------------------------------------------------------
# Step 7: Wait for certificates to be issued
# ------------------------------------------------------------------
- name: Wait for apps wildcard certificate to be ready
kubernetes.core.k8s_info:
api_version: cert-manager.io/v1
kind: Certificate
namespace: openshift-ingress
name: apps-wildcard-cert
register: __sno_deploy_apps_cert
until: >-
__sno_deploy_apps_cert.resources | length > 0 and
(__sno_deploy_apps_cert.resources[0].status.conditions | default([])
| selectattr('type', '==', 'Ready')
| selectattr('status', '==', 'True') | list | length > 0)
retries: "{{ (sno_deploy_certificate_wait_timeout / 10) | int }}"
delay: 10
- name: Wait for API server certificate to be ready
kubernetes.core.k8s_info:
api_version: cert-manager.io/v1
kind: Certificate
namespace: openshift-config
name: api-server-cert
register: __sno_deploy_api_cert
until: >-
__sno_deploy_api_cert.resources | length > 0 and
(__sno_deploy_api_cert.resources[0].status.conditions | default([])
| selectattr('type', '==', 'Ready')
| selectattr('status', '==', 'True') | list | length > 0)
retries: "{{ (sno_deploy_certificate_wait_timeout / 10) | int }}"
delay: 10
# ------------------------------------------------------------------
# Step 8: Patch IngressController and APIServer to use the certs
# ------------------------------------------------------------------
- name: Patch default IngressController to use LetsEncrypt cert
kubernetes.core.k8s:
state: present
merge_type: merge
definition:
apiVersion: operator.openshift.io/v1
kind: IngressController
metadata:
name: default
namespace: openshift-ingress-operator
spec:
defaultCertificate:
name: apps-wildcard-tls
- name: Patch APIServer to use LetsEncrypt cert
kubernetes.core.k8s:
state: present
merge_type: merge
definition:
apiVersion: config.openshift.io/v1
kind: APIServer
metadata:
name: cluster
spec:
servingCerts:
namedCertificates:
- names:
- "{{ __sno_deploy_api_hostname }}"
servingCertificate:
name: api-server-tls
# ------------------------------------------------------------------
# Step 9: Wait for rollouts
# ------------------------------------------------------------------
- name: Wait for API server to begin restart
ansible.builtin.pause:
seconds: 30
- name: Wait for router pods to restart with new cert
kubernetes.core.k8s_info:
api_version: apps/v1
kind: Deployment
namespace: openshift-ingress
name: router-default
register: __sno_deploy_router
until: >-
__sno_deploy_router.resources is defined and
__sno_deploy_router.resources | length > 0 and
(__sno_deploy_router.resources[0].status.updatedReplicas | default(0)) ==
(__sno_deploy_router.resources[0].status.replicas | default(1)) and
(__sno_deploy_router.resources[0].status.readyReplicas | default(0)) ==
(__sno_deploy_router.resources[0].status.replicas | default(1))
retries: 60
delay: 10
- name: Display cert-manager configuration summary
ansible.builtin.debug:
msg:
- "cert-manager configuration complete!"
- " ClusterIssuer : letsencrypt-production"
- " Apps wildcard : {{ __sno_deploy_apps_wildcard }}"
- " API cert : {{ __sno_deploy_api_hostname }}"
verbosity: 1