Skip to content
This repository was archived by the owner on Mar 16, 2024. It is now read-only.

Commit fb452e6

Browse files
authored
Merge pull request #1800 from StrongMonkey/use-cert-manager
Drop built-in http01 challenge, use cert-manager to issue certs for custom domain
2 parents 3e9c9a9 + 8891f3d commit fb452e6

File tree

31 files changed

+965
-362
lines changed

31 files changed

+965
-362
lines changed

docs/docs/100-reference/01-command-line/acorn_install.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ acorn install
2828
--auto-upgrade-interval string For apps configured with automatic upgrades enabled, the interval at which to check for new versions. Upgrade intervals configured at the application level cannot be smaller than this. (default '5m' - 5 minutes)
2929
--aws-identity-provider-arn string ARN of cluster's OpenID Connect provider registered in AWS
3030
--builder-per-project Create a dedicated builder per project
31+
--cert-manager-issuer string The name of the cert-manager cluster issuer to use for TLS certificates on custom domains
3132
--cluster-domain strings The externally addressable cluster domain (default .oss-acorn.io)
3233
--controller-replicas int acorn-controller deployment replica count
3334
--controller-service-account-annotation strings annotation to apply to the acorn-system service account

docs/docs/50-running/03-certificates.md

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
title: TLS Certificates
33
---
44

5-
Applications that publish HTTP endpoints can be protected by TLS certificates. If you've enabled Acorn's [Let's Encrypt integration](30-installation/02-options.md#tls-via-lets-encrypt), a valid certificate will be provisioned for your app's endpoints. This applies to oss-acorn.io generated endpoints and custom endpoints configured using the [publish flag](50-running/02-networking.md#publish-individual-ports).
5+
Applications that publish HTTP endpoints can be protected by TLS certificates. If you've enabled Acorn's [Let's Encrypt integration](30-installation/02-options.md#tls-via-lets-encrypt), a valid certificate will be provisioned for your app's endpoints. This only applies to oss-acorn.io generated endpoints. For custom endpoints configured using the [publish flag](50-running/02-networking.md#publish-individual-ports), Acorn relies on external cert-manager to issue certificates. For more information on how to configure cert-manager, see [Issuing custom domain certs](#issuing-custom-domain-certs).
66

77
## Manually adding certificates
88
If you don't wish to use Acorn's Let's Encrypt integration, you can configure certificates manually or by integrating with cert-manager. Acorn will automatically look for SANs in secrets of type `kubernetes.io/tls` for the exposed FQDN of the application in the Acorn namespace.
@@ -53,3 +53,33 @@ acorn run -p my-app.example.com:web [MY_APP_IMAGE]
5353

5454
Acorn will automatically inspect each certificate in the Acorn namespace for one that can be used with `my-app.example.com`.
5555
If no TLS secret is found with that FQDN, it will be exposed on HTTP only.
56+
57+
### Issuing custom domain certs
58+
59+
Acorn's Let's Encrypt integration does not issue certificates for custom domains. Instead, you will rely on external cert-manager to issue certificates. To do so, you will need to create a cluster-issuer first. For more information on how to install and configure cert-manager, see [cert-manager docs](https://cert-manager.io/docs/).
60+
61+
```yaml
62+
apiVersion: cert-manager.io/v1
63+
kind: ClusterIssuer
64+
metadata:
65+
name: letsencrypt-prod
66+
spec:
67+
acme:
68+
server: https://acme-v02.api.letsencrypt.org/directory
69+
70+
privateKeySecretRef:
71+
name: letsencrypt-prod
72+
solvers:
73+
- http01:
74+
ingress:
75+
ingressClassName: traefik
76+
```
77+
78+
Modify the `ingressClassName` to match the ingress controller you are using. For example, if you are using the NGINX ingress controller, you will need to change it to `nginx`.
79+
Once you have created the cluster-issuer, pass the cluster-issuer's name to `acorn install` so that Acorn knows which cluster-issuer to apply to the ingress resource.
80+
81+
Once you have created the cluster issuer, pass the cluster issuer's name to acorn install so that acorn knows where to apply the cluster issuer to the ingress resource.
82+
83+
```shell
84+
acorn install --cert-manager-issuer=letsencrypt-prod
85+
```

pkg/apis/api.acorn.io/v1/types.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,7 @@ type Config struct {
432432
AWSIdentityProviderARN *string `json:"awsIdentityProviderArn" name:"aws-identity-provider-arn" usage:"ARN of cluster's OpenID Connect provider registered in AWS"`
433433
EventTTL *string `json:"eventTTL" name:"event-ttl" usage:"Amount of time an Acorn event will be stored before being deleted (default '168h' - 7 days)"`
434434
Features map[string]bool `json:"features" name:"features" boolmap:"true" usage:"Enable or disable features. (example foo=true,bar=false)"`
435+
CertManagerIssuer *string `json:"certManagerIssuer" name:"cert-manager-issuer" usage:"The name of the cert-manager cluster issuer to use for TLS certificates on custom domains" default:""`
435436
}
436437

437438
type EncryptionKey struct {

pkg/apis/api.acorn.io/v1/zz_generated.deepcopy.go

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/config/config.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,9 @@ func complete(ctx context.Context, c *apiv1.Config, getter kclient.Reader) error
115115
}
116116
}
117117
}
118+
if c.CertManagerIssuer == nil {
119+
c.CertManagerIssuer = new(string)
120+
}
118121
return nil
119122
}
120123

@@ -372,6 +375,10 @@ func merge(oldConfig, newConfig *apiv1.Config) *apiv1.Config {
372375
mergedConfig.EventTTL = newConfig.EventTTL
373376
}
374377

378+
if newConfig.CertManagerIssuer != nil {
379+
mergedConfig.CertManagerIssuer = newConfig.CertManagerIssuer
380+
}
381+
375382
return &mergedConfig
376383
}
377384

pkg/controller/routes.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ func routes(router *router.Router, cfg *rest.Config, registryTransport http.Roun
6161
appRouter.HandlerFunc(appdefinition.PullAppImage(registryTransport, recorder))
6262
appRouter.HandlerFunc(images.CreateImages)
6363
appRouter.HandlerFunc(appdefinition.ParseAppImage)
64-
appRouter.HandlerFunc(tls.ProvisionCerts) // Provision TLS certificates for port bindings with user-defined (valid) domains
6564
appRouter.Middleware(appdefinition.FilterLabelsAndAnnotationsConfig).HandlerFunc(namespace.AddNamespace)
6665
appRouter.Middleware(jobs.NeedsDestroyJobFinalization).FinalizeFunc(jobs.DestroyJobFinalizer, jobs.FinalizeDestroyJob)
6766

pkg/controller/service/service_test.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,3 +109,18 @@ func TestRouter(t *testing.T) {
109109
func TestSecret(t *testing.T) {
110110
tester.DefaultTest(t, scheme.Scheme, "testdata/secret", RenderServices)
111111
}
112+
113+
// TestSettingUpDefaultCertManager tests that the default cert-manager annotation is set up on custom domain if no matching certs is found
114+
func TestSettingUpDefaultCertManager(t *testing.T) {
115+
tester.DefaultTest(t, scheme.Scheme, "testdata/ingress/cert-manager", RenderServices)
116+
}
117+
118+
// TestCustomCertsShouldNotSetCertManager tests that the default cert-manager annotation should not be setup on custom domain if matching certs is found
119+
func TestCustomCertsShouldNotSetCertManager(t *testing.T) {
120+
tester.DefaultTest(t, scheme.Scheme, "testdata/ingress/customdomainwithcerts", RenderServices)
121+
}
122+
123+
// TestCustomCertsWithAnnonationsShouldNotSetCertManagerDefaultIssuer tests that the default cert-manager annotation should not be setup on custom domain if cert-manager annotations is already set
124+
func TestCustomCertsWithAnnonationsShouldNotSetCertManagerDefaultIssuer(t *testing.T) {
125+
tester.DefaultTest(t, scheme.Scheme, "testdata/ingress/customdomainwithannotations", RenderServices)
126+
}

pkg/controller/service/testdata/ingress/basic/expected.golden

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,14 +70,14 @@ apiVersion: networking.k8s.io/v1
7070
kind: Ingress
7171
metadata:
7272
annotations:
73-
acorn.io/targets: '{"ci1.acorn.not":{"port":81,"service":"oneimage"},"localhost":{"port":81,"service":"oneimage"},"oneimage-app-name-a5b0aade.local.oss-acorn.io":{"port":81,"service":"oneimage"}}'
73+
acorn.io/targets: '{"oneimage-app-name-a5b0aade.local.oss-acorn.io":{"port":81,"service":"oneimage"}}'
7474
creationTimestamp: null
7575
labels:
7676
acorn.io/app-name: app-name
7777
acorn.io/app-namespace: app-namespace
7878
acorn.io/container-name: oneimage
7979
acorn.io/managed: "true"
80-
name: oneimage
80+
name: oneimage-cluster-domain
8181
namespace: app-created-namespace
8282
spec:
8383
rules:
@@ -91,6 +91,25 @@ spec:
9191
number: 81
9292
path: /
9393
pathType: Prefix
94+
status:
95+
loadBalancer: {}
96+
97+
---
98+
apiVersion: networking.k8s.io/v1
99+
kind: Ingress
100+
metadata:
101+
annotations:
102+
acorn.io/targets: '{"ci1.acorn.not":{"port":81,"service":"oneimage"},"localhost":{"port":81,"service":"oneimage"}}'
103+
creationTimestamp: null
104+
labels:
105+
acorn.io/app-name: app-name
106+
acorn.io/app-namespace: app-namespace
107+
acorn.io/container-name: oneimage
108+
acorn.io/managed: "true"
109+
name: oneimage-custom-domain
110+
namespace: app-created-namespace
111+
spec:
112+
rules:
94113
- host: ci1.acorn.not
95114
http:
96115
paths:
@@ -179,7 +198,7 @@ status:
179198
type: defined
180199
endpoints:
181200
- address: oneimage-app-name-a5b0aade.local.oss-acorn.io
182-
publishProtocol: https
201+
publishProtocol: http
183202
- address: ci1.acorn.not
184203
publishProtocol: https
185204
- address: localhost
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
apiVersion: v1
2+
data:
3+
config: '{"certManagerIssuer":"default"}'
4+
kind: ConfigMap
5+
metadata:
6+
name: acorn-config
7+
namespace: acorn-system
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
`apiVersion: v1
2+
kind: Service
3+
metadata:
4+
creationTimestamp: null
5+
labels:
6+
acorn.io/app-name: app-name
7+
acorn.io/app-namespace: app-namespace
8+
acorn.io/container-name: oneimage
9+
acorn.io/managed: "true"
10+
name: oneimage
11+
namespace: app-created-namespace
12+
spec:
13+
ports:
14+
- appProtocol: HTTP
15+
name: "81"
16+
port: 81
17+
protocol: TCP
18+
targetPort: 81
19+
- name: "90"
20+
port: 90
21+
protocol: TCP
22+
targetPort: 91
23+
- name: "92"
24+
port: 92
25+
protocol: TCP
26+
targetPort: 92
27+
selector:
28+
acorn.io/app-name: app-name
29+
acorn.io/app-namespace: app-namespace
30+
acorn.io/container-name: oneimage
31+
acorn.io/managed: "true"
32+
type: ClusterIP
33+
status:
34+
loadBalancer: {}
35+
36+
---
37+
apiVersion: v1
38+
kind: Service
39+
metadata:
40+
creationTimestamp: null
41+
labels:
42+
acorn.io/app-name: app-name
43+
acorn.io/app-namespace: app-namespace
44+
acorn.io/container-name: oneimage
45+
acorn.io/managed: "true"
46+
acorn.io/service-publish: "true"
47+
name: oneimage-publish-1234567890ab
48+
namespace: app-created-namespace
49+
spec:
50+
ports:
51+
- name: "90"
52+
port: 90
53+
protocol: TCP
54+
targetPort: 91
55+
- name: "92"
56+
port: 92
57+
protocol: TCP
58+
targetPort: 92
59+
selector:
60+
acorn.io/app-name: app-name
61+
acorn.io/app-namespace: app-namespace
62+
acorn.io/container-name: oneimage
63+
acorn.io/managed: "true"
64+
type: LoadBalancer
65+
status:
66+
loadBalancer: {}
67+
68+
---
69+
apiVersion: networking.k8s.io/v1
70+
kind: Ingress
71+
metadata:
72+
annotations:
73+
acorn.io/targets: '{"oneimage-app-name-a5b0aade.local.oss-acorn.io":{"port":81,"service":"oneimage"}}'
74+
creationTimestamp: null
75+
labels:
76+
acorn.io/app-name: app-name
77+
acorn.io/app-namespace: app-namespace
78+
acorn.io/container-name: oneimage
79+
acorn.io/managed: "true"
80+
name: oneimage-cluster-domain
81+
namespace: app-created-namespace
82+
spec:
83+
rules:
84+
- host: oneimage-app-name-a5b0aade.local.oss-acorn.io
85+
http:
86+
paths:
87+
- backend:
88+
service:
89+
name: oneimage
90+
port:
91+
number: 81
92+
path: /
93+
pathType: Prefix
94+
status:
95+
loadBalancer: {}
96+
97+
---
98+
apiVersion: networking.k8s.io/v1
99+
kind: Ingress
100+
metadata:
101+
annotations:
102+
acorn.io/targets: '{"ci1.acorn.not":{"port":81,"service":"oneimage"},"localhost":{"port":81,"service":"oneimage"}}'
103+
cert-manager.io/cluster-issuer: default
104+
creationTimestamp: null
105+
labels:
106+
acorn.io/app-name: app-name
107+
acorn.io/app-namespace: app-namespace
108+
acorn.io/container-name: oneimage
109+
acorn.io/managed: "true"
110+
name: oneimage-custom-domain
111+
namespace: app-created-namespace
112+
spec:
113+
rules:
114+
- host: ci1.acorn.not
115+
http:
116+
paths:
117+
- backend:
118+
service:
119+
name: oneimage
120+
port:
121+
number: 81
122+
path: /
123+
pathType: Prefix
124+
- host: localhost
125+
http:
126+
paths:
127+
- backend:
128+
service:
129+
name: oneimage
130+
port:
131+
number: 81
132+
path: /
133+
pathType: Prefix
134+
tls:
135+
- hosts:
136+
- ci1.acorn.not
137+
secretName: oneimage-cm-cert-1
138+
- hosts:
139+
- localhost
140+
secretName: oneimage-cm-cert-2
141+
status:
142+
loadBalancer: {}
143+
144+
---
145+
apiVersion: internal.acorn.io/v1
146+
kind: ServiceInstance
147+
metadata:
148+
creationTimestamp: null
149+
labels:
150+
acorn.io/app-name: app-name
151+
acorn.io/app-namespace: app-namespace
152+
acorn.io/container-name: oneimage
153+
acorn.io/managed: "true"
154+
name: oneimage
155+
namespace: app-created-namespace
156+
uid: 1234567890abcdef
157+
spec:
158+
appName: app-name
159+
appNamespace: app-namespace
160+
container: oneimage
161+
default: false
162+
labels:
163+
acorn.io/app-name: app-name
164+
acorn.io/app-namespace: app-namespace
165+
acorn.io/container-name: oneimage
166+
acorn.io/managed: "true"
167+
ports:
168+
- protocol: http
169+
publish: true
170+
targetPort: 81
171+
- port: 90
172+
protocol: tcp
173+
publish: true
174+
targetPort: 91
175+
- protocol: tcp
176+
publish: true
177+
targetPort: 92
178+
publish:
179+
- hostname: localhost
180+
- hostname: ci1.acorn.not
181+
status:
182+
conditions:
183+
reason: Success
184+
status: "True"
185+
success: true
186+
type: defined
187+
endpoints:
188+
- address: oneimage-app-name-a5b0aade.local.oss-acorn.io
189+
publishProtocol: http
190+
- address: ci1.acorn.not
191+
publishProtocol: https
192+
- address: localhost
193+
publishProtocol: https
194+
hasService: true
195+
`

0 commit comments

Comments
 (0)