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

Commit c33b54e

Browse files
committed
Streamline manifests geneation
* Use single source of truth config.jsonnet * Setup oauth2 clients in Dex configuration * Fix externaldns on Digitalocean and AWS * Use a single label domain Signed-off-by: Christian Simon <[email protected]>
1 parent e1acda9 commit c33b54e

File tree

9 files changed

+204
-244
lines changed

9 files changed

+204
-244
lines changed

demo/Makefile

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,7 @@ KUBECONFIG := $(CURDIR)/.kubeconfig-$(CLOUD)
66

77
GOOGLE_PROJECT := $(shell gcloud config get-value core/project)
88

9-
ifeq ($(CLOUD),google)
10-
EXT_VARS ?= "master=true,cloud=$(CLOUD)"
11-
else
12-
EXT_VARS ?= "master=false,cloud=$(CLOUD)"
13-
endif
9+
EXT_VARS := --tla-str cloud=$(CLOUD)
1410

1511
UNAME_S := $(shell uname -s)
1612
ifeq ($(UNAME_S),Linux)
@@ -50,23 +46,22 @@ manifests/$(CLOUD)-config.json:
5046

5147
.PHONY: manifests_apply
5248
manifests_apply: depend manifests/$(CLOUD)-config.json ## Use kubecfg to apply manifests into cluster
53-
rm -f manifests/config.json && ln -s $(CLOUD)-config.json manifests/config.json
5449
# apply all CRDs
55-
$(BINDIR)/kubecfg -V ${EXT_VARS} show config.jsonnet --format json | sed 's#^---$$##' | jq 'select(.kind == "CustomResourceDefinition")' | kubectl apply -f -
50+
$(BINDIR)/kubecfg $(EXT_VARS) show config.jsonnet --format json | sed 's#^---$$##' | jq 'select(.kind == "CustomResourceDefinition")' | kubectl apply -f -
5651
# apply everything
57-
$(BINDIR)/kubecfg -V ${EXT_VARS} show config.jsonnet | kubectl apply -f -
52+
$(BINDIR)/kubecfg $(EXT_VARS) show config.jsonnet | kubectl apply -f -
5853

5954
.PHONY: manifests_validate
6055
manifests_validate: depend manifests/$(CLOUD)-config.json ## Use kubecfg to validate manifests
61-
$(BINDIR)/kubecfg -V ${EXT_VARS} validate config.jsonnet
56+
$(BINDIR)/kubecfg $(EXT_VARS) validate config.jsonnet
6257

6358
.PHONY: manifests_validate
6459
jsonnet_fmt: depend ## validate formatting of jsonnet files
6560
$(BINDIR)/jsonnet fmt --test $(shell find manifests/components/. manifests/main.jsonnet -name "*.jsonnet")
6661

6762
.PHONY: manifests_destroy
6863
manifests_destroy: depend manifests/$(CLOUD)-config.json ## Use kubecfg to delete manifests
69-
$(BINDIR)/kubecfg -V ${EXT_VARS} show config.jsonnet | kubectl delete -f - --ignore-not-found
64+
$(BINDIR)/kubecfg $(EXT_VARS) show config.jsonnet | kubectl delete -f - --ignore-not-found
7065

7166
.PHONY: manifests_backup_certificates
7267
manifests_backup_certificates:

demo/README.md

Lines changed: 66 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
11
# Multi-Cluster Tutorial
22

3-
This document will walk-through how to create two managed Kubernetes clusters on
4-
separate providers (GKE and EKS), deploying:
5-
- [Dex](https://github.com/dexidp/dex) as the OIDC issuer for both clusters.
6-
- [Gangway](https://github.com/heptiolabs/gangway) web server to authenticate
7-
users to Dex and help generate Kubeconfig files.
3+
This document will walk-through how to create three managed Kubernetes clusters on
4+
separate providers (Google, Amazon and Digitalocean), deploying:
5+
6+
- [Dex](https://github.com/dexidp/dex) as the OIDC issuer for both clusters.
7+
8+
- [Gangway](https://github.com/heptiolabs/gangway) web server to authenticate
9+
users to Dex and help generate Kubeconfig files.
10+
811
- [kube-oidc-proxy](https://github.com/jetstack/kube-oidc-proxy) to expose both
912
clusters to OIDC authentication.
13+
1014
- [Contour](https://github.com/heptio/contour) as the ingress controller with
1115
TLS SNI passthrough enabled.
16+
1217
- [Cert-Manager](https://github.com/jetstack/cert-manager) to issue and manage
1318
certificates.
1419

@@ -17,17 +22,19 @@ supports, namely, username and password, and GitHub, however [more are
1722
available.](https://github.com/dexidp/dex#connectors)
1823

1924
## Prerequisites
25+
2026
The tutorial will be using Cert-Manager to generate certificates signed by
21-
[Let's Encrypt](https://letsencrypt.org/) for components in both GKE and EKS
22-
using a DNS challenge. Although not the only way to generate certificates, the
23-
tutorial assumes that a domain will be used which belongs to your Google Cloud
24-
project, and records of sub-domains of this domain will be created to assign DNS
25-
to the components. A Google Cloud Service Account will be created to manage
26-
these DNS challenges and it's secrets passed to Cert-Manager.
27+
[Let's Encrypt](https://letsencrypt.org/) for components in all clouds using a
28+
DNS challenge. Although not the only way to generate certificates, the tutorial
29+
assumes that a domain will be used which belongs to your Google Cloud project,
30+
and records of sub-domains of this domain will be created to assign DNS to the
31+
components. A Google Cloud Service Account will be created to manage these DNS
32+
challenges and it's secrets passed to Cert-Manager.
2733

2834
A Service Account has been created for Terraform with its secrets stored at
2935
`~/.config/gcloud/terraform-admin.json`. The Service Account needs at least
3036
these IAM Roles attached:
37+
3138
```
3239
Compute Admin
3340
Kubernetes Engine Admin
@@ -43,57 +50,73 @@ relevent permissions to create a fully fledged cluster, including creating
4350
load balancers, instance pools etc. Typically, these environment variables must
4451
be set when running `terraform` and deploying the manifests before OIDC
4552
authentication has been set up:
53+
4654
```
4755
AWS_SECRET_ACCESS_KEY
4856
AWS_SESSION_TOKEN
4957
AWS_ACCESS_KEY_ID
5058
```
5159

60+
For Digitalocean you need to get an write token from the console and export it
61+
using this environment variable:
62+
63+
```
64+
DIGITALOCEAN_TOKEN
65+
```
66+
5267
## Infrastructure
68+
5369
First the GKE and EKS cluster will be created, along with secrets to be used for
5470
OIDC authentication for each cluster. The Amazon Terraform module has dependant
5571
resources on the Google module, so the Google module must be created first.
5672

5773
```
58-
CLOUD=google make terraform_apply
59-
CLOUD=amazon make terraform_apply
74+
CLOUD=google make terraform_apply
75+
CLOUD=amazon make terraform_apply
76+
CLOUD=digitalocean make terraform_apply
6077
```
6178

62-
This will create a standard Kubernetes cluster in both EKS and GKE, a Service
79+
This will create a Kubernetes cluster in EKS and GKE, a Service
6380
Account to manage Google Cloud DNS records for DNS challenges and OIDC secrets
6481
for both clusters. It should generate a JSON configuration file for both
6582
clusters in `./manifests/google-config.json` and `./manifests/amazon.json`
6683
respectively.
6784

68-
6985
## Configuration
70-
Copy `config.dist.jsonnet` to both `gke-config.jsonnet` and `eks-config.jsonnet`.
71-
These two files will hold configuration for setting up the OIDC authentication
72-
in both clusters as well as assigning DNS. Firstly, determine what sub-domain
73-
will be used for either cluster, using a domain you own in your Google Cloud
74-
Project, e.g.
86+
87+
Copy `config.dist.jsonnet` to `config.jsonnet`. This file will hold
88+
configuration for setting up the OIDC authentication in all clusters as well as
89+
assigning DNS. Firstly, determine what `base_domain` will be used for this
90+
demo. Ensure the `base_domain` starts with a `.`.
91+
92+
The domain, which needs to be managed in Google Cloud DNS will have records
93+
like this:
94+
7595
```
76-
gke.mydomain.company.net
77-
eks.mydomain.company.net
96+
dex.mydomain.company.net
97+
gangway-gke.mydomain.company.net
98+
gangway-eks.mydomain.company.net
99+
gangway-dok.mydomain.company.net
78100
```
79101

80-
Populate each configuration file with its corresponding domain and Let's
81-
Encrypt contract email.
102+
Populate the configuration file with its corresponding domain
103+
(`.mydomain.company.net` in our example) and Let's Encrypt contact email.
82104

83-
### GKE
105+
### Dex customisations
84106

85-
Since the GKE cluster will be hosting Dex, the OIDC issuer, its
86-
configuration file must contain how or what users will use to authenticate. Here
87-
we will show two methods, username and password, and GitHub.
107+
Since the GKE cluster will be hosting Dex, the OIDC issuer, its configuration
108+
file must contain how or what users will use to authenticate. Here we will show
109+
two methods, username and password, and GitHub.
88110

89111
Usernames and passwords can be populated with the following block within the
90112
`dex` block.
91113

92114
```
93-
dex+: {
115+
dex+: if $.master then {
94116
users: [
95117
$.dex.Password('[email protected]', '$2y$10$i2.tSLkchjnpvnI73iSW/OPAVriV9BWbdfM6qemBM1buNRu81.ZG.'), // plaintext: secure
96118
],
119+
} else {
97120
},
98121
```
99122

@@ -108,11 +131,12 @@ htpasswd -bnBC 10 "" MyVerySecurePassword | tr -d ':'
108131
Dex also supports multiple 'connectors' that enable third party applications to
109132
provide OAuth to it's system. For GitHub, this involves creating an 'OAuth App'.
110133
The `Authorization callback URL` should be populated with the Dex callback URL, i.e.
111-
`https://dex.gke.mydomain.company.net/callback`.
134+
`https://dex.gke.mydomain.company.net/callback`.
112135
The resulting `Client ID` and `Client Secret` can then be used to populate the
113136
configuration file:
137+
114138
```
115-
dex+: {
139+
dex+: if $.master then {
116140
connectors: [
117141
$.dex.Connector('github', 'GitHub', 'github', {
118142
clientID: 'myGithubAppClientID',
@@ -122,88 +146,19 @@ configuration file:
122146
}],
123147
}),
124148
],
149+
} else {
125150
},
126151
```
127152

128153
You can find more information on GitHub OAuth apps
129154
[here.](https://developer.github.com/v3/oauth/)
130155

131-
Finally, Dex needs to be configured to also accept the Gangway client in the EKS
132-
cluster. To do this, we add a `dex.Client` block in the configuration. We need to
133-
populate its redirect URL as well as the client ID and client secret using
134-
values that were created in the `./manifests/amazon-config.json` by Terraform.
135-
The resulting block should would look like:
136-
137-
```
138-
eksClient: $.dex.Client('my_client_id_in_./manifests/amazon-config.json') + $.dex.metadata {
139-
secret: 'my_client_secret_in_./manifests/amazon-config.json',
140-
redirectURIs: [
141-
'https://gangway.eks.mydomain.company.net/callback',
142-
],
143-
},
144-
```
145-
146-
The resulting `gke-config.jsonnet` file should look similar to
147-
148-
```
149-
(import './manifests/main.jsonnet') {
150-
base_domain: 'gke.mydomain.company.net',
151-
152-
cert_manager+: {
153-
letsencrypt_contact_email:: '[email protected]',
154-
},
155-
156-
dex+: {
157-
users: [
158-
$.dex.Password('[email protected]', '$2y$10$i2.tSLkchjnpvnI73iSW/OPAVriV9BWbdfM6qemBM1buNRu81.ZG.'), // plaintext: secure
159-
],
160-
161-
connectors: [
162-
$.dex.Connector('github', 'GitHub', 'github', {
163-
clientID: 'myGithubAppClientID',
164-
clientSecret: 'myGithubAppClientSecret',
165-
orgs: [{
166-
name: 'company',
167-
}],
168-
}),
169-
],
170-
},
171-
172-
eksClient: $.dex.Client('my_client_id_in_./manifests/amazon-config.json') + $.dex.metadata {
173-
secret: 'my_client_secret_in_./manifests/amazon-config.json',
174-
redirectURIs: [
175-
'https://gangway.eks.mydomain.company.net/callback',
176-
],
177-
},
178-
}
179-
```
180-
181-
### EKS
182-
183-
The EKS cluster will not be hosting the dex server so only needs to be
184-
configured with its domain, Dex's domain and the Let's Encrypt contact email.
185-
The resuting `eks-config.jsonnet` file should look similar to:
186-
187-
```
188-
(import './manifests/main.jsonnet') {
189-
base_domain: 'eks.mydomain.company.net',
190-
dex_domain: 'dex.gke.mydomain.company.net',
191-
cert_manager+: {
192-
letsencrypt_contact_email:: '[email protected]',
193-
},
194-
}
195-
```
196-
197156
## Deployment
198157

199-
Once the configuration files have been created the manifests can be deployed.
200-
Copy or create a symbolic link from the `gke-config.jsonnet` file to
201-
`config.jsonnet` and apply.
158+
Once the configuration file has been created the manifests can be deployed.
202159

203160
```
204-
$ ln -s gke-config.jsonnet config.jsonnet
205-
$ export CLOUD=google
206-
$ make manifests_apply
161+
$ CLOUD=google manifests_apply
207162
```
208163

209164
You should then see the components deployed to the cluster in the `auth`
@@ -219,6 +174,7 @@ gangway-77dfdb68d-x84hj 0/1 ContainerCreating 0 11s
219174
```
220175

221176
Verify that the ingress has been configured to what you were expecting.
177+
222178
```
223179
$ kubectl get ingressroutes -n auth
224180
```
@@ -234,31 +190,17 @@ $ kubectl get -n auth secret
234190
```
235191

236192
You can save these certifcates locally, and restore them any time using:
193+
237194
```
238195
$ make manifests_backup_certificates
239196
$ make manifests_restore_certificates
240197
```
241198

242-
An `A` record can now be created so that DNS can be resolve the Contour Load
243-
Balancer public IP address. Take a note of the external-IP address exposed:
244-
245-
```
246-
$ kubectl get svc contour -n auth
247-
```
248-
249-
Create a wildcard `A` record (matching all sub-domains), with some
250-
reasonable TTL pointing to the exposed IP address of the Contour Load Balancer.
251-
252-
```
253-
DNS name: *.gke.mydomain.company.net
254-
Record resource type: A
255-
IPv4 address: $CONTOUR_IP
256-
```
257-
258199
You can check that the DNS record has been propagated by trying to resolve it
259200
using:
201+
260202
```
261-
$ host https://gangway.gke.mydomain.company.net
203+
$ host https://gangway-gke.mydomain.company.net
262204
```
263205

264206
Once propagated, you can then visit the Gangway URL, follow the instructions and
@@ -267,28 +209,20 @@ kube-oidc-proxy. Trying the Kubeconfig, you should be greeted with an error
267209
message that your OIDC username does not have enough RBAC permissions to access
268210
that resource.
269211

270-
The EKS cluster manifests can now be deployed using the `eks-config.jsonnet`.
212+
The EKS and Digitalocean cluster manifests can now be deployed:
271213

272214
```
273-
$ rm config.jsonnet && ln -s eks-config.jsonnet config.jsonnet
274-
$ export CLOUD=amazon
275-
$ make manifests_apply
215+
$ CLOUD=amazon manifests_apply
216+
$ CLOUD=digitalocean manifests_apply
276217
```
277218

278219
Get the AWS DNS URL for the Contour Load Balancer.
220+
279221
```
280222
$ export KUBECONFIG=.kubeconfig-amazon
281223
$ kubectl get svc -n auth
282224
```
283225

284-
Once the the Contour Load Balancer has an external URL, we need to create a `CNAME`
285-
record:
286-
```
287-
DNS name: *.eks.mydomain.company.net
288-
Record resource type: CNAME
289-
Canonical name: $CONTOUR_AWS_URL
290-
```
291-
292226
When components have their TLS secrets, you will then be able to login to the
293227
Gangway portal on EKS and download your Kubeconfig. Again, when trying this
294228
Kubeconfig, you will initially be greeted with an "unauthorized" error message

demo/config.dist.jsonnet

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
(import './manifests/main.jsonnet') {
2-
base_domain: 'kubernetes.example.net',
3-
// dex_domain: 'dex.kubernetes.example.net', // to be used on non dex hosting clusters
1+
function(cloud='google') (import './manifests/main.jsonnet') {
2+
cloud: cloud,
3+
base_domain: '.kubernetes.example.net',
44
cert_manager+: {
55
letsencrypt_contact_email:: '[email protected]',
66
},
7-
dex+: {
7+
dex+: if $.master then {
88
users: [
99
$.dex.Password('[email protected]', '$2y$10$i2.tSLkchjnpvnI73iSW/OPAVriV9BWbdfM6qemBM1buNRu81.ZG.'), // plaintext: secure
1010
],
@@ -18,13 +18,6 @@
1818
}],
1919
}),
2020
],
21+
} else {
2122
},
22-
23-
// Here we can register more dex clients
24-
//extraClient: $.dex.Client('123') + $.dex.metadata {
25-
// secret: '4567',
26-
// redirectURIs: [
27-
// 'https://gangway.other.kubernetes.example.net/callback',
28-
// ],
29-
//},
3023
}

0 commit comments

Comments
 (0)