Skip to content

Commit eaf2619

Browse files
authored
Merge pull request #287 from mbaldessari/letsencrypt
Add an experimental letsencypt chart
2 parents 5978a08 + 7572b82 commit eaf2619

17 files changed

+1387
-1
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ helmlint: ## run helm lint
110110
@for t in $(CHARTS); do common/scripts/lint.sh $$t $(TEST_OPTS); if [ $$? != 0 ]; then exit 1; fi; done
111111

112112
API_URL ?= https://raw.githubusercontent.com/hybrid-cloud-patterns/ocp-schemas/main/openshift/4.10/
113-
KUBECONFORM_SKIP ?= -skip 'CustomResourceDefinition'
113+
KUBECONFORM_SKIP ?= -skip 'CustomResourceDefinition,ClusterIssuer,CertManager,Certificate'
114114
# We need to skip 'CustomResourceDefinition' as openapi2jsonschema seems to be unable to generate them ATM
115115
.PHONY: kubeconform
116116
kubeconform: ## run helm kubeconform

letsencrypt/.helmignore

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Patterns to ignore when building packages.
2+
# This supports shell glob matching, relative path matching, and
3+
# negation (prefixed with !). Only one pattern per line.
4+
.DS_Store
5+
# Common VCS dirs
6+
.git/
7+
.gitignore
8+
.bzr/
9+
.bzrignore
10+
.hg/
11+
.hgignore
12+
.svn/
13+
# Common backup files
14+
*.swp
15+
*.bak
16+
*.tmp
17+
*.orig
18+
*~
19+
# Various IDEs
20+
.project
21+
.idea/
22+
*.tmproj
23+
.vscode/

letsencrypt/Chart.yaml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
apiVersion: v2
2+
name: letsencrypt
3+
description: A Helm chart to add letsencrypt support to Validated Patterns
4+
5+
type: application
6+
7+
# This is the chart version. This version number should be incremented each time you make changes
8+
# to the chart and its templates, including the app version.
9+
# Versions are expected to follow Semantic Versioning (https://semver.org/)
10+
version: 0.1.0
11+
12+
# This is the version number of the application being deployed. This version number should be
13+
# incremented each time you make changes to the application. Versions are not expected to
14+
# follow Semantic Versioning. They should reflect the version the application is using.
15+
# It is recommended to use it with quotes.
16+
appVersion: "1.16.0"

letsencrypt/README.md

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# Letsencrypt support for Validated patterns
2+
3+
This is an *EXPERIMENTAL* and *UNSUPPORTED* chart to enable letsencrypt support in the pattern.
4+
Currently the only supported cloud for this is AWS.
5+
6+
In order to enable this chart in your patterns, please add and edit the following lines to `values-AWS.yaml`:
7+
8+
letsencrypt:
9+
region: eu-central-1 # region of the cluster
10+
server: https://acme-v02.api.letsencrypt.org/directory
11+
# staging URL
12+
# server: https://acme-staging-v02.api.letsencrypt.org/directory
13+
email: foo@bar.it
14+
15+
clusterGroup:
16+
applications:
17+
letsencrypt:
18+
name: letsencrypt
19+
namespace: letsencrypt
20+
project: default
21+
path: common/letsencrypt
22+
23+
Once the above is enabled in a pattern, a certain amount of time (~15/20 minutes or so) is needed for all the cluster operators to settle, all the HTTPS routes will have a wildcard certificate signed by letsencrypt. By default also the API endpoint will use a certificate signed by letsencrypt.
24+
25+
## Limitations
26+
27+
Please be aware of the following gotchas when using this chart:
28+
29+
1. Once the API certificate has been replaced with the letsencrypt one, the `oc` commands might fail with x509 unknown certificate authority errors.
30+
You need to remove the previous CA from the kubeconfig file. Run: `oc config set-cluster <clustername> --certificate-authority="/dev/null" --embed-certs`
31+
2. When you switch to non-staging letsencrypt certificates, things might fail if you asked for too many certificates over the last few days.
32+
3. The cluster takes ~20-30 mins to fully settle when both the API endpoint and the default ingress certificates are implemented
33+
34+
## Implementation
35+
36+
This chart creates a Cloud Credential that is allowed to write and read DNS entries via Route53 in AWS. That credential is then used by cert-manager to prove ownership of the DNS zone and answer the ACME DNS01 challenges.
37+
We ask for a single wildcard certificate for the default Ingress *.apps.domain and one non-wildcard certificate for the API endpoint api.domain.
38+
We use Argo's Server-Side Apply feature to patch in the Ingress Controller and the API endpoint certificates.
39+
Currently we also patch the main cluster-wide Argo instance to set the tls route to `reencrypt` in order have a proper cert there. Once issue 297 in the gitops-operator repository is fixed, we can drop that.
40+
41+
## Parameters
42+
43+
### global parameters
44+
45+
This section contains the global parameters consumed by this chart
46+
47+
| Name | Description | Value |
48+
| --------------------------- | ---------------------------------------------------------------------------------------------------- | ------------------ |
49+
| `global.localClusterDomain` | String containing the domain including the apps. prefix. Gets set by the Validated Pattern framework | `apps.example.com` |
50+
51+
### letsencrypt parameters
52+
53+
This section contains all the parameters for the letsencrypt
54+
chart in order to request CA signed certificates in a Validated Pattern
55+
56+
| Name | Description | Value |
57+
| -------------------------------- | --------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------- |
58+
| `letsencrypt.enabled` | Boolean to enable this feature and request a wildcard cert for the default Infress (*.apps.domain) (defaults to True) | `true` |
59+
| `letsencrypt.api_endpoint` | Boolean to enable letsencrypt certs on the API endpoint too (defaults to True) | `true` |
60+
| `letsencrypt.region` | String that defines the region used by the route53/dns01 resolver in cert-manager (required) | `eu-central-1` |
61+
| `letsencrypt.email` | String containing the email used when requesting certificates to letsencrypt (required) | `test@example.com` |
62+
| `letsencrypt.server` | String containing the letsencrypt ACME URL (Defaults to the staging server) | `https://acme-staging-v02.api.letsencrypt.org/directory` |
63+
| `letsencrypt.organizations` | List of organization names to be put in a certificate (Defaults to [hybrid-cloud-patterns.io]) | `["hybrid-cloud-patterns.io"]` |
64+
| `letsencrypt.usages` | List of certificate uses. See API cert-manager.io/v1.KeyUsage (Defaults to [server auth]) | `["server auth"]` |
65+
| `letsencrypt.duration` | Duration of the requested letsencrypt certificates (Defaults to 168h0m0s) | `168h0m0s` |
66+
| `letsencrypt.renewBefore` | How long before expiration date should the certs be renewed (Defaults to 28h0m0s) | `28h0m0s` |
67+
| `letsencrypt.nameservers` | List of DNS server (ip:port strings) to be used when doing DNS01 challenges (Defaults to [8.8.8.8:53, 1.1.1.1:53]) | `["8.8.8.8:53","1.1.1.1:53"]` |
68+
| `letsencrypt.certmanagerChannel` | String the channel to install cert-manager from (Defaults to "stable-v1") | `stable-v1` |
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{{ if and (.Values.letsencrypt.enabled) (.Values.letsencrypt.api_endpoint) }}
2+
apiVersion: cert-manager.io/v1
3+
kind: Certificate
4+
metadata:
5+
name: api-validated-patterns-cert
6+
namespace: openshift-config
7+
annotations:
8+
argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true
9+
spec:
10+
secretName: api-validated-patterns-letsencrypt-cert
11+
duration: {{ .Values.letsencrypt.duration }}
12+
renewBefore: {{ .Values.letsencrypt.renewBefore }}
13+
commonName: 'api.{{ $.Values.global.localClusterDomain | replace "apps." "" }}'
14+
usages:
15+
{{- range .Values.letsencrypt.usages }}
16+
- {{ . }}
17+
{{- end }}
18+
dnsNames:
19+
- api.{{ $.Values.global.localClusterDomain | replace "apps." "" }}
20+
issuerRef:
21+
name: validated-patterns-issuer
22+
kind: ClusterIssuer
23+
subject:
24+
organizations:
25+
{{- range .Values.letsencrypt.organizations }}
26+
- {{ . }}
27+
{{- end }}
28+
{{- end }}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
{{ if .Values.letsencrypt.enabled }}
2+
---
3+
apiVersion: operators.coreos.com/v1alpha1
4+
kind: Subscription
5+
metadata:
6+
name: openshift-cert-manager-operator
7+
namespace: cert-manager-operator
8+
spec:
9+
channel: "{{ .Values.letsencrypt.certmanagerChannel }}"
10+
installPlanApproval: Automatic
11+
name: openshift-cert-manager-operator
12+
source: redhat-operators
13+
sourceNamespace: openshift-marketplace
14+
---
15+
apiVersion: operators.coreos.com/v1
16+
kind: OperatorGroup
17+
metadata:
18+
name: cert-manager-operator
19+
namespace: cert-manager-operator
20+
spec:
21+
targetNamespaces:
22+
- cert-manager-operator
23+
---
24+
apiVersion: operator.openshift.io/v1alpha1
25+
kind: CertManager
26+
metadata:
27+
name: cluster
28+
annotations:
29+
argocd.argoproj.io/sync-options: ServerSideApply=true, Validate=false, SkipDryRunOnMissingResource=true
30+
spec:
31+
managementState: "Managed"
32+
unsupportedConfigOverrides:
33+
# Here's an example to supply custom DNS settings.
34+
controller:
35+
args:
36+
- "--dns01-recursive-nameservers={{ with index .Values.letsencrypt.nameservers 0 }}{{ . }}{{- end }},{{ with index .Values.letsencrypt.nameservers 1 }}{{ . }}{{- end }}"
37+
- "--dns01-recursive-nameservers-only"
38+
{{- end }}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{{ if .Values.letsencrypt.enabled }}
2+
apiVersion: cloudcredential.openshift.io/v1
3+
kind: CredentialsRequest
4+
metadata:
5+
name: letsencrypt-cert-manager-dns
6+
namespace: openshift-cloud-credential-operator
7+
annotations:
8+
argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true
9+
spec:
10+
providerSpec:
11+
apiVersion: cloudcredential.openshift.io/v1
12+
kind: AWSProviderSpec
13+
statementEntries:
14+
- action:
15+
- 'route53:ChangeResourceRecordSets'
16+
- 'route53:GetChange'
17+
- 'route53:ListHostedZonesByName'
18+
- 'route53:ListHostedZones'
19+
effect: Allow
20+
resource: '*'
21+
secretRef:
22+
name: cert-manager-dns-credentials
23+
namespace: cert-manager
24+
{{- end }}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
{{ if .Values.letsencrypt.enabled }}
2+
---
3+
apiVersion: operator.openshift.io/v1
4+
kind: IngressController
5+
metadata:
6+
name: default
7+
namespace: openshift-ingress-operator
8+
annotations:
9+
argocd.argoproj.io/sync-options: ServerSideApply=true, Validate=false, SkipDryRunOnMissingResource=true
10+
spec:
11+
routeAdmission:
12+
wildcardPolicy: WildcardsAllowed
13+
defaultCertificate:
14+
name: lets-encrypt-wildcart-cert-tls
15+
# Patch the cluster-wide argocd instance so it uses the ingress tls cert
16+
---
17+
apiVersion: argoproj.io/v1alpha1
18+
kind: ArgoCD
19+
metadata:
20+
name: openshift-gitops
21+
namespace: openshift-gitops
22+
annotations:
23+
argocd.argoproj.io/sync-options: ServerSideApply=true, Validate=false, SkipDryRunOnMissingResource=true
24+
spec:
25+
server:
26+
route:
27+
enabled: true
28+
tls:
29+
termination: reencrypt
30+
{{ if .Values.letsencrypt.api_endpoint }}
31+
---
32+
apiVersion: config.openshift.io/v1
33+
kind: APIServer
34+
metadata:
35+
name: cluster
36+
annotations:
37+
argocd.argoproj.io/sync-options: ServerSideApply=true, Validate=false, SkipDryRunOnMissingResource=true
38+
spec:
39+
servingCerts:
40+
namedCertificates:
41+
- names:
42+
- api.{{ $.Values.global.localClusterDomain | replace "apps." "" }}
43+
servingCertificate:
44+
name: api-validated-patterns-letsencrypt-cert
45+
{{- end }}
46+
{{- end }}

letsencrypt/templates/issuer.yaml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{{ if .Values.letsencrypt.enabled }}
2+
apiVersion: cert-manager.io/v1
3+
kind: ClusterIssuer
4+
metadata:
5+
name: validated-patterns-issuer
6+
annotations:
7+
argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true
8+
spec:
9+
acme:
10+
server: {{ .Values.letsencrypt.server }}
11+
email: {{ .Values.letsencrypt.email }}
12+
privateKeySecretRef:
13+
name: validated-patterns-issuer-account-key
14+
solvers:
15+
- selector: {}
16+
dns01:
17+
route53:
18+
region: {{ .Values.letsencrypt.region }}
19+
accessKeyIDSecretRef:
20+
name: cert-manager-dns-credentials
21+
key: aws_access_key_id
22+
secretAccessKeySecretRef:
23+
name: cert-manager-dns-credentials
24+
key: aws_secret_access_key
25+
{{- end }}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{{ if .Values.letsencrypt.enabled }}
2+
apiVersion: v1
3+
kind: Namespace
4+
metadata:
5+
name: cert-manager-operator
6+
spec:
7+
---
8+
apiVersion: v1
9+
kind: Namespace
10+
metadata:
11+
name: cert-manager
12+
spec:
13+
---
14+
apiVersion: v1
15+
kind: Namespace
16+
metadata:
17+
name: letsencrypt
18+
spec:
19+
---
20+
{{- end }}

0 commit comments

Comments
 (0)