Skip to content

Commit

Permalink
Merge pull request #32 from gardener/certmanager
Browse files Browse the repository at this point in the history
cert-manager component
  • Loading branch information
Diaphteiros authored Jul 2, 2019
2 parents c7b5c5c + 4a46abf commit 310aa9d
Show file tree
Hide file tree
Showing 26 changed files with 464 additions and 40 deletions.
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,10 @@ landscape:
- email: # see above
username: # see above
hash: # bcrypted hash of password, see above

<a href="#landscapecert-manager">cert-manager</a>:
email: # email for acme registration
server: &lt;live|staging|self-signed|url&gt; # which kind of certificates to use for the dashboard/identity ingress (defaults to `self-signed`)
</pre>


Expand Down Expand Up @@ -305,6 +309,32 @@ identity:
Configures the identity provider that allows access to the Gardener dashboard. The easiest method is to provide a list of `users`, each containing `email`, `username`, and either a clear-text `password` or a bcrypted `hash` of the password.
You can then login into the dashboard using one of the specified email/password combinations.
### landscape.cert-manager
```yaml
cert-manager:
email:
server: <live|staging|self-signed|url>
```
The setup deploys a [cert-manager](https://github.com/jetstack/cert-manager) to provide a certificate for the Gardener dashboard, which can be configured here.
The entire `landscape.cert-manager` block is optional.
If not specified, `landscape.cert-manager.server` defaults to `self-signed`. This means, that a selfs-signed CA will be created, which is used by the cert-manager (using a [CA issuer](https://docs.cert-manager.io/en/latest/tasks/issuers/setup-ca.html)) to sign the certificate. Since the CA is not publicly trusted, your webbrowser will show a 'untrusted certificate' warning when accessing the dashboard.
The `landscape.cert-manager.email` field is not evaluated in `self-signed` mode.
If set to `live`, the cert-manager will use the [letsencrypt](https://letsencrypt.org/) ACME server to get trusted certificates for the dashboard. Beware the [rate limits](https://letsencrypt.org/docs/rate-limits/) of letsencrypt.
Letsencrypt requires an email address and will send information about expiring certificates to that address. If `landscape.cert-manager.email` is not specified, `landscape.identity.users[0].email` will be used. One of the two fields has to be present.
If set to `staging`, the cert-manager will use the letsencrypt staging server. This is for testing purposes mainly. The communication with letsencrypt works exactly as for the `live` case, but the staging server does not produce trusted certificates, so you will still get the browser warning. The rate limits are significantly higher for the staging server, though.
If set to anything else, it is assumed to be the URL of an ACME server and the setup will create an [ACME issuer](https://docs.cert-manager.io/en/latest/tasks/issuers/setup-acme/index.html) for it.
See the [extended configuration](docs/extended/cert-manager.md) for more configuration options.
## Uninstall Gardener
1. Run `sow delete -A` to delete all components from your base Kubernetes cluster in inverse order.
Expand Down
43 changes: 42 additions & 1 deletion acre.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,19 @@ landscape:
image_tag: (( valid( tag ) ? tag :~~ ))
image_repo: (( ~~ ))
repo: "https://github.com/gardener/external-dns-management.git"
cert-manager:
controller:
<<: (( merge ))
tag: (( valid( branch ) -or valid( commit ) ? ~~ :helm_tag )) # only used for CRDs
repo: "https://github.com/jetstack/cert-manager.git"
helm_repo: "https://charts.jetstack.io"
helm_tag: "v0.8.0"
cert-dns-bridge:
<<: (( merge ))
tag: (( valid( branch ) -or valid( commit ) ? ~~ :"1.0.0" ))
image_tag: (( valid( tag ) ? tag :~~ ))
image_repo: (( ~~ ))
repo: "https://github.com/gardener/certificate-dns-bridge.git"
iaas: (( merge none // map[ select[stub()|e|-> ( ! defined( e.mode ) ) -or ( e.mode != "inactive" ) ] |idx,v|-> v { "mode" = v.mode || "seed" } ] ))
etcd:
<<: (( merge ))
Expand All @@ -140,6 +153,9 @@ landscape:
dashboard: (( ~~ ))
identity:
gardener: (( ~~ ))
cert-manager:
<<: (( merge ))
server: (( merge none // valid( stub() ) ? ( type( stub() ) == "map" ? stub() :{ "url" = stub() } ) :{"url" = "self-signed"} ))
dns:
<<: (( merge ))
type: (( .dns_type_mapping[iaas[0].type] ))
Expand Down Expand Up @@ -170,6 +186,7 @@ validation:
### AUXILIARY FUNCTIONS ###
return_true: (( |x|-> true ))
instantiate_validator: (( |values,validator|-> *validator ))
email_regex: "[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*@[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)+$"

### VALIDATOR DEFINITIONS ###
types:
Expand Down Expand Up @@ -308,6 +325,28 @@ validation:
- ["mapfield", "nodes", "cidr"]
- ["mapfield", "pods", "cidr"]
- ["mapfield", "services", "cidr"]
cert-manager_validators:
basic:
- and
- - optionalfield
- email
- - match
- (( validation.email_regex ))
- - mapfield
- server
- - and
- - mapfield
- url
- - or
- ["valueset", ["self-signed", "staging", "live"]]
- dnsdomain
- - optionalfield
- ca
- ["and", [(( cert-manager_validators.selfsigned )), (( landscape.cert-manager.server.url ))], [(( cert-manager_validators.acme )), (( landscape.cert-manager.server.url ))]]
selfsigned: (( |ca,url|-> [url == "self-signed" ? valid( ca.crt ) -and valid( ca.key ) :true, "valid", "if 'landscape.cert-manager.server.url' is set to 'self-signed', you should either specify a CA with key ('server.ca.crt' and 'server.ca.key' set), or no CA at all ('server.ca' node not present)"] ))
acme: (( |ca,url|-> [url != "self-signed" ? valid( ca.crt ) -and ( ! defined( ca.key ) ) :true, "if 'landscape.cert-manager.server.url' is not set to 'self-signed', you should either specify a CA without key ('server.ca.crt' set, no 'server.ca.key'), or the 'server.ca' node should not be present at all"] ))
email: (( |ca,id|-> [valid( ca.email ) -or valid( id.users[0].email ), "either 'landscape.cert-manager.email' or 'landscape.identity.users[0].email' needs to be set"] ))



### VALIDATIONS ###
Expand Down Expand Up @@ -341,14 +380,16 @@ validation:
gardener: (( defined( landscape.gardener ) ? validate( landscape.gardener, validation.gardener_validator ) :~~ ))
##### landscape.dashboard
dashboard: (( defined( landscape.dashboard ) ? validate( landscape.dashboard, validation.dashboard_validator ) :~~ ))
##### landscape.certmanager
cert-manager: (( validate( landscape.cert-manager, validation.cert-manager_validators.basic, [validation.cert-manager_validators.email, landscape.identity] ) ))
##### landscape.identity TODO
identity:
userspec:
- and
- - mapfield
- email
- - match
- "[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*@[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)+$"
- (( validation.email_regex ))
- - mapfield
- username
- - or
Expand Down
4 changes: 4 additions & 0 deletions acre.yaml.example
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,7 @@ landscape:
- email: "[email protected]"
username: "Admin"
password: "MyHardPassword123$"

# cert-manager:
# email: "[email protected]"
# server: live
13 changes: 13 additions & 0 deletions components/cert-manager/cert/action
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#
# remove this file if no dedicated deploy or delete code
# is required
#
deploy()
{
true
}

delete()
{
true
}
12 changes: 12 additions & 0 deletions components/cert-manager/cert/component.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
component:
imports:
- cert-manager/solver
- cert-controller: cert-manager/controller
- namespace
- ingress-controller

stubs:
- lib/templates/utilities.yaml
- lib/templates/certs.yaml
- lib/templates/state.yaml
32 changes: 32 additions & 0 deletions components/cert-manager/cert/deployment.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
imports: (( &temporary ))
landscape: (( &temporary ))

settings:
certificate:
name: dashboard-identity-ingress
domain: (( "*." imports.ingress-controller.export.ingress_domain ))
secret_name: identity-dashboard-tls
namespace: (( landscape.namespace ))

plugins:
- kubectl: cert
- -echo: "The export generation waits for the certificate, which may take some time."

cert:
kubeconfig: (( .landscape.clusters[0].kubeconfig ))
manifests:
- apiVersion: certmanager.k8s.io/v1alpha1
kind: Certificate
metadata:
name: (( .settings.certificate.name ))
namespace: (( .settings.certificate.namespace ))
spec:
secretName: (( .settings.certificate.secret_name ))
renewBefore: 360h # 15d
commonName: (( .settings.certificate.domain ))
dnsNames:
- (( .settings.certificate.domain ))
issuerRef:
name: (( imports.cert-controller.export.issuerName ))
kind: Issuer
34 changes: 34 additions & 0 deletions components/cert-manager/cert/export.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
settings: (( &temporary ))
landscape: (( &temporary ))
env: (( &temporary ))

wait_for_certificate:
<<: (( &temporary ))
check_command:
- "kubectl"
- "--kubeconfig"
- (( lookup_file(landscape.clusters.[0].kubeconfig, env.ROOTDIR).[0] ))
- "-n"
- (( .settings.certificate.namespace ))
- "get"
- "certificate"
- (( .settings.certificate.name ))
- "-o"
- "json"
get_command:
- "kubectl"
- "--kubeconfig"
- (( lookup_file(landscape.clusters.[0].kubeconfig, env.ROOTDIR).[0] ))
- "-n"
- (( .settings.certificate.namespace ))
- "get"
- "secret"
- (( .settings.certificate.secret_name ))
- "-o"
- "json"
result: (( sync( exec_uncached( check_command ), value.status.conditions[0].status == "True", wait_for_certificate.b64dall( exec( get_command ).data ), 600 ) ))
b64dall: (( |x|-> sum[x|{}|s,k,v|-> s {k=base64_decode(v)}] ))

export:
<<: (( .settings ))
11 changes: 11 additions & 0 deletions components/cert-manager/controller/component.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
component:
imports:
- tiller
- dns-controller
- namespace

stubs:
- lib/templates/utilities.yaml
- lib/templates/certs.yaml
- lib/templates/state.yaml
131 changes: 131 additions & 0 deletions components/cert-manager/controller/deployment.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
---
imports: (( &temporary ))
landscape: (( &temporary ))
utilities: (( &temporary ))

settings:
groupName: cert.gardener.cloud
solverName: certificate-dns-bridge
namespace: cert-manager # will be created - don't choose an existing one!
serviceAccountName: cert-manager
self-signed: (( .caSpec.url == "self-signed" ))
issuerName: (( .settings.self-signed ? "ca-issuer" :"acme-issuer" ))
caSecret: "self-signed-ca"
ca:
given: (( &temporary ( valid( .caSpec.ca.crt ) -and ( ( ! .settings.self-signed ) -or valid( .caSpec.ca.key ) ) ) )) # a given CA needs crt and key for self-signed mode
crt: (( given ? .caSpec.ca.crt :( .state.ca.value.cert || ~~ ) ))
key: (( given ? ( .caSpec.ca.key || ~~ ) :( .state.ca.value.key || ~~ ) ))

caSpec:
<<: (( &temporary ))
instantiateIfNeeded: (( |x|-> type( x ) == "template" ? *x :x ))
server: (( caSpec.instantiateIfNeeded( .servers[.landscape.cert-manager.server.url] || .landscape.cert-manager.server ) ))
url: (( server.url || server ))
ca: (( server.ca || ~~ ))

plugins:
- git
- chart-checkout
- kubectl: namespace
- kubectl: crds
- helm
- -echo: (( .settings.self-signed ? ( .settings.ca.given ? "Using provided CA" :"Using self-signed CA" ) :"Using ACME server at " .caSpec.url ))
- kubectl: issuer

git:
<<: (( landscape.versions.cert-manager.controller ))
files:
- "deploy/manifests/00-crds.yaml"

chart-checkout:
repo: (( landscape.versions.cert-manager.controller.helm_repo ))
name: cert-manager
version: (( landscape.versions.cert-manager.controller.helm_tag ))

namespace:
name: (( settings.namespace ))
kubeconfig: (( landscape.clusters.[0].kubeconfig ))
manifests:
- apiVersion: v1
kind: Namespace
metadata:
labels:
certmanager.k8s.io/disable-validation: "true"
name: (( .namespace.name ))

crds:
kubeconfig: (( landscape.clusters.[0].kubeconfig ))
files:
- "git/repo/deploy/manifests/00-crds.yaml"

issuer: (( .settings.self-signed ? *ca_issuer :*acme_issuer ))

acme_issuer:
<<: (( &template &temporary ))
kubeconfig: (( landscape.clusters.[0].kubeconfig ))
manifests:
- apiVersion: certmanager.k8s.io/v1alpha1
kind: Issuer
metadata:
name: (( settings.issuerName ))
namespace: (( .landscape.namespace ))
spec:
acme:
server: (( .caSpec.url ))
email: (( .landscape.cert-manager.email || .landscape.identity.users[0].email ))
privateKeySecretRef:
name: (( settings.issuerName "-secret" ))
solvers:
- dns01:
webhook:
groupName: (( settings.groupName ))
solverName: (( settings.solverName ))
config:
dns-class: (( .imports.dns-controller.export.dns-class ))
namespace: (( .imports.dns-controller.export.namespace ))

ca_issuer:
<<: (( &template &temporary ))
kubeconfig: (( landscape.clusters.[0].kubeconfig ))
manifests:
- apiVersion: v1
kind: Secret
metadata:
name: (( .settings.caSecret ))
namespace: (( .landscape.namespace ))
type: kubernetes.io/tls
data:
tls.crt: (( base64( .settings.ca.crt ) ))
tls.key: (( base64( .settings.ca.key ) ))
- apiVersion: certmanager.k8s.io/v1alpha1
kind: Issuer
metadata:
name: (( settings.issuerName ))
namespace: (( .landscape.namespace ))
spec:
ca:
secretName: (( .settings.caSecret ))


servers:
<<: (( &temporary ))
live: https://acme-v02.api.letsencrypt.org/directory
staging:
<<: (( &template )) # to not download the letsencrypt certs every time
url: https://acme-staging-v02.api.letsencrypt.org/directory
ca:
crt: (( exec( "curl", "-s", "https://letsencrypt.org/certs/fakelerootx1.pem" ) "\n" exec( "curl", "-s", "https://letsencrypt.org/certs/fakeleintermediatex1.pem" ) ))

helm:
kubeconfig: (( landscape.clusters.[0].kubeconfig ))
source: "chart-checkout/charts/cert-manager"
name: cert-manager
namespace: (( .namespace.name ))
values:
serviceAccount:
create: true
name: (( .settings.serviceAccountName ))

state:
<<: (( &state(merge none) ))
ca: (( .settings.self-signed -and ( ! .settings.ca.given ) ? ( utilities.certs.selfSignedCA("self-signed-ca", false) ) :~~ ))
4 changes: 4 additions & 0 deletions components/cert-manager/controller/export.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
settings: (( &temporary ))

export: (( settings ))
8 changes: 8 additions & 0 deletions components/cert-manager/solver/component.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
component:
imports:
- tiller
- dns-controller
- cert-controller: cert-manager/controller

stubs: []
Loading

0 comments on commit 310aa9d

Please sign in to comment.