diff --git a/README.md b/README.md index da2197a..f4fa0f0 100644 --- a/README.md +++ b/README.md @@ -112,7 +112,7 @@ git clone https://github.com/kurokobo/awx-on-k3s.git cd awx-on-k3s ``` -Generate a Self-Signed Certificate. Note that IP address can't be specified. +Generate a Self-Signed certificate. Note that IP address can't be specified. If you want to use a certificate from public ACME CA such as Let's Encrypt or ZeroSSL instead of Self-Signed certificate, follow the guide on [📁 **Use SSL Certificate from Public ACME CA**](acme) first and come back to this step when done. ```bash AWX_HOST="awx.example.com" diff --git a/acme/README.md b/acme/README.md new file mode 100644 index 0000000..93b5666 --- /dev/null +++ b/acme/README.md @@ -0,0 +1,165 @@ + +# Use SSL Certificate from Public ACME CA + +If you want to use a certificate from public ACME CA such as Let's Encrypt or ZeroSSL instead of Self-Signed certificate, some additional steps are required. + + +## Table of Contents + +- [Concepts](#concepts) +- [Procedure](#procedure) + - [Deploy cert-manager](#deploy-cert-manager) + - [Prepare Issuer](#prepare-issuer) + - [Modify configuration files for AWX](#modify-configuration-files-for-awx) + +## Concepts + +In order to use a valid SSL certificate issued by public ACME CA for Ingress, you we to run some kind of ACME client software. + +Traefik, the default Ingress controller for K3s, has a built-in ACME client, but it is a bit complicated to make it work, so in this guide, we will use [cert-manager](https://cert-manager.io/). + +To issue a certificate from the ACME CA using [cert-manager](https://cert-manager.io/), we must first create [an Issuer or ClusterIssuer](https://cert-manager.io/docs/concepts/issuer/) resource that contains the account information to be registered with the ACME CA and the information to be used for the HTTP-01 and DNS-01 challenges. + +Once the Issuer has been created, simply specify the Issuer in the annotation of the Ingress resource, and cert-manager will do all the necessary work automatically. + +Fortunately, AWX Operator has a parameter to add arbitrary annotations to Ingress, so protecting our AWX instance with a certificate from a public ACME CA is a breeze. + +In this example, we will use: + +- [**DNS-01** challenge](https://cert-manager.io/docs/configuration/acme/dns01/) +- with [**Azure DNS**](https://cert-manager.io/docs/configuration/acme/dns01/azuredns/) +- with [**Service Principal**](https://cert-manager.io/docs/configuration/acme/dns01/azuredns/#service-principal) + +This guide does not provide any information how to configure Azure, other DNS services, or how to use HTTP-01 challenge here. Please refer to the document of cert-manager for details. + +- [Configure Issuer for DNS-01 challenge](https://cert-manager.io/docs/configuration/acme/dns01/) +- [Configure Issuer for HTTP-01 challenge](https://cert-manager.io/docs/configuration/acme/http01/) + +## Procedure + +### Deploy cert-manager + +Deploy cert-manager first. + +```bash +kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.6.1/cert-manager.yaml +``` + +Ensure the pods in `cert-manager` namespace are running. + +```bash +$ kubectl -n cert-manager get pod +NAME READY STATUS RESTARTS AGE +cert-manager-55658cdf68-rfqmf 1/1 Running 0 21h +cert-manager-cainjector-967788869-xnq2n 1/1 Running 0 21h +cert-manager-webhook-6668fbb57d-r9dmj 1/1 Running 0 21h +``` + +### Prepare Issuer + +To use **DNS-01** challenge with **Azure DNS** with **Service Principal**, the following information is required. + +- **Client ID** + - [Azure Active Directory] > [App registrations] > Your Application > [Application ID] +- **Client Secret** + - [Azure Active Directory] > [App registrations] > Your Application > [Certificates & secrets] > [Client secrets] > [Value] +- **Subscription ID** + - [DNS zones] > Your Zone > [Subscription ID] +- **Tenant ID** + - [Azure Active Directory] > [Properties] > [Tenant ID] +- **Name of Resource Group** + - [DNS zones] > Your Zone > [Resource group] +- **Name of DNS Zone** + - [DNS zones] > Your Zone + +Then modify required fields in `acme/issuer.yaml`. + +```yaml +... +spec: + acme: + email: cert@example.com 👈👈👈 + + server: https://acme-staging-v02.api.letsencrypt.org/directory 👈👈👈 + + privateKeySecretRef: + name: awx-issuer-account-key + + solvers: + - dns01: + azureDNS: + clientID: 00000000-0000-0000-0000-000000000000 👈👈👈 + subscriptionID: 00000000-0000-0000-0000-000000000000 👈👈👈 + tenantID: 00000000-0000-0000-0000-000000000000 👈👈👈 + resourceGroupName: example-rg 👈👈👈 + hostedZoneName: example.com 👈👈👈 + environment: AzurePublicCloud + clientSecretSecretRef: + name: azuredns-config + key: client-secret +``` + +To store Client Secret for the Service Principal to Secret resouce in Kubernetes, modify `acme/kustomization.yaml`. + +```yaml +... + - name: azuredns-config + type: Opaque + literals: + - client-secret=0000000000000000000000000000000000 👈👈👈 +... +``` + +Once the file has been modified to suit your environment, deploy the Issuer. + +```bash +kubectl apply -k acme +``` + +Ensure your Issuer exists in `awx` namespace. + +```bash +$ kubectl -n awx get issuer +NAME READY AGE +awx-issuer True 21h +``` + +### Modify configuration files for AWX + +Now that we have an Issuer, the last step is to add annotations to Ingress. A few files under the `base` directory need to be modified. + +In `base/awx.yaml`, correct `hostname` to the FQDN which the certificate will be issued, and add `ingress_annotations` parameter to specify which Issuer will be used. + +```yaml +spec: + ... + ingress_type: ingress + ingress_tls_secret: awx-secret-tls + hostname: awx.example.com 👈👈👈 + + ingress_annotations: | 👈👈👈 + cert-manager.io/issuer: awx-issuer 👈👈👈 +``` + +Finally, comment out or delete all of the `awx-secret-tls` part in `base/kustomization.yaml`, as the actual contents of `awx-secret-tls` are automatically managed by cert-manager and do not need to be specified manually. + +```yaml +... +generatorOptions: + disableNameSuffixHash: true + +secretGenerator: + # - name: awx-secret-tls 👈👈👈 + # type: kubernetes.io/tls 👈👈👈 + # files: 👈👈👈 + # - tls.crt 👈👈👈 + # - tls.key 👈👈👈 + + - name: awx-postgres-configuration + type: Opaque +... +``` + +Now your configuration files to ready to use ACME CA. Go back [`README.md`](https://github.com/kurokobo/awx-on-k3s#prepare-required-files) and proceed the procedure. + +Once the AWX instance is up and running, we can access it over HTTPS and we will see that our AWX protected by a valid SSL certificate. diff --git a/acme/issuer.yaml b/acme/issuer.yaml new file mode 100644 index 0000000..f5b1270 --- /dev/null +++ b/acme/issuer.yaml @@ -0,0 +1,31 @@ +--- +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: awx-issuer +spec: + acme: + # The email address to be registered with ACME CA + email: cert@example.com + + # The URL of the ACME API endpoint. + # In Let's Encrypt, this is one of the following: + # Production: https://acme-v02.api.letsencrypt.org/directory + # Staging : https://acme-staging-v02.api.letsencrypt.org/directory + server: https://acme-staging-v02.api.letsencrypt.org/directory + + privateKeySecretRef: + name: awx-issuer-account-key + + solvers: + - dns01: + azureDNS: + clientID: 00000000-0000-0000-0000-000000000000 + subscriptionID: 00000000-0000-0000-0000-000000000000 + tenantID: 00000000-0000-0000-0000-000000000000 + resourceGroupName: example-rg + hostedZoneName: example.com + environment: AzurePublicCloud + clientSecretSecretRef: + name: azuredns-config + key: client-secret diff --git a/acme/kustomization.yaml b/acme/kustomization.yaml new file mode 100644 index 0000000..43cf90a --- /dev/null +++ b/acme/kustomization.yaml @@ -0,0 +1,17 @@ +--- +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +namespace: awx + +generatorOptions: + disableNameSuffixHash: true + +secretGenerator: + - name: azuredns-config + type: Opaque + literals: + - client-secret=0000000000000000000000000000000000 + +resources: + - namespace.yaml + - issuer.yaml diff --git a/acme/namespace.yaml b/acme/namespace.yaml new file mode 100644 index 0000000..e24dd13 --- /dev/null +++ b/acme/namespace.yaml @@ -0,0 +1,5 @@ +--- +apiVersion: v1 +kind: Namespace +metadata: + name: awx