Skip to content
This repository has been archived by the owner on Jul 3, 2019. It is now read-only.

Commit

Permalink
Add cert-manager for TLS certificates
Browse files Browse the repository at this point in the history
  • Loading branch information
cablespaghetti committed Dec 16, 2018
1 parent 74a5a4e commit 8b38534
Show file tree
Hide file tree
Showing 6 changed files with 160 additions and 3 deletions.
13 changes: 10 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ Current features:
* Automatic backup and recovery. So if your master gets terminated, when the replacement is provisioned by AWS it will pick up where the old one left off without you doing anything. 😁
* Completely automated provisioning through Terraform and Bash.
* Variables for many things including number of workers (provisioned using an auto-scaling group) and EC2 instance type.
* [External DNS](https://github.com/kubernetes-incubator/external-dns) and [Nginx Ingess](https://github.com/kubernetes/ingress-nginx) as a cheap ELB alternative.
* Helm Tiller (currently v2.12.0)
* [External DNS](https://github.com/kubernetes-incubator/external-dns) and [Nginx Ingess](https://github.com/kubernetes/ingress-nginx) as a cheap ELB alternative, with [Cert Manager](https://github.com/jetstack/cert-manager) for TLS certificates via Let's Encrypt.
* Auto Scaling of worker nodes, if you enable the [Cluster AutoScaler](https://github.com/kubernetes/autoscaler/tree/master/cluster-autoscaler).
* Persistent Volumes using GP2 storage on EBS.

Expand All @@ -22,10 +23,11 @@ Current features:
2. [Install Terraform](https://www.terraform.io/intro/getting-started/install.html)
3. Generate token: `python -c 'import random; print "%0x.%0x" % (random.SystemRandom().getrandbits(3*8), random.SystemRandom().getrandbits(8*8))' > token.txt`
4. Make an SSH key on us-east-1 from the AWS console
5. Run terraform plan: `terraform plan -var k8s-ssh-key=<aws-ssh-key-name> -var k8stoken=$(cat token.txt) -var admin-cidr-blocks="<my-public-ip-address>/32" -var nginx-ingress-domain="ingress.mydomain.com"`
5. Run terraform plan: `terraform plan -var k8s-ssh-key=<aws-ssh-key-name> -var k8stoken=$(cat token.txt) -var admin-cidr-blocks="<my-public-ip-address>/32" -var nginx-ingress-domain="ingress.mydomain.com" -var cert-manager-email="myemail@address.com"`
6. Build out infrastructure: `terraform apply -var k8s-ssh-key=<aws-ssh-key-name> -var k8stoken=$(cat token.txt) -var admin-cidr-blocks="<my-public-ip-address>/32"`
7. SSH to K8S master and run something: `ssh ubuntu@$(terraform output master_dns) -i <aws-ssh-key-name>.pem kubectl get no`
10. Done!
8. The [Cert Manager Issuer](manifests/cert-manager-issuer.yaml.tmpl) for Let's Encrypt has been applied to the default namespace. You will also need to apply it to any other namespaces you want to obtain TLS certificates for.
9. Done!

Optional Variables:

Expand All @@ -43,8 +45,13 @@ Optional Variables:
* `external-dns-enabled` - Set to "0" to disable ExternalDNS (1 by default) - Existing Route 53 Domain required
* `nginx-ingress-enabled` - Set to "0" to disable Nginx Ingress (1 by default)
* `nginx-ingress-domain` - The DNS name to map to Nginx Ingress using External DNS ("" by default)
* `cert-manager-enabled` - Set to "0" to disabled Cert Manager (1 by default)
* `cert-manager-email` - The email address to use for Let's Encrypt certificate requests ("" by default)
* `cluster-autoscaler-enabled` - Set to "1" to enable the cluster autoscaler (0 by default)

### Examples
* [Nginx deployment](examples/nginx.yaml)

### Ingress Notes

As hinted above, this uses Nginx Ingress as an alternative to a Load Balancer. This is done by exposing ports 443 and 80 directly on each of the nodes (Workers and the Master) using a NodePort type Service. Unfortunately External DNS doesn't seem to work with Nginx Ingress when you expose it in this way, so I've had to just map a single DNS name (using the nginx-ingress-domain variable) to the NodePort service itself. External DNS will keep that entry up to date with the IPs of the nodes in the cluster; you will then have to manually add CNAME entries for your individual services.
Expand Down
91 changes: 91 additions & 0 deletions examples/nginx.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
k8s-app: nginx
name: nginx
spec:
replicas: 1
revisionHistoryLimit: 1
selector:
matchLabels:
k8s-app: nginx
template:
metadata:
labels:
k8s-app: nginx
spec:
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: "k8s-app"
operator: In
values:
- nginx
topologyKey: "kubernetes.io/hostname"
- weight: 90
podAffinityTerm:
labelSelector:
matchExpressions:
- key: "k8s-app"
operator: In
values:
- nginx
topologyKey: "failure-domain.beta.kubernetes.io/zone"
containers:
- name: nginx
image: nginx:1-alpine
ports:
- name: nginx
containerPort: 80
livenessProbe:
initialDelaySeconds: 5
httpGet:
path: /
port: nginx
readinessProbe:
initialDelaySeconds: 5
httpGet:
path: /
port: nginx
---
apiVersion: v1
kind: Service
metadata:
labels:
k8s-app: nginx
name: nginx
spec:
ports:
- name: http
port: 80
targetPort: nginx
selector:
k8s-app: nginx
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: nginx-test-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
certmanager.k8s.io/issuer: "letsencrypt-prod"
certmanager.k8s.io/acme-challenge-type: http01
spec:
tls:
- hosts:
- awesomenginx.mydomain.com
secretName: awesomenginx-https
rules:
- host: awesomenginx.mydomain.com
http:
paths:
- path: /
backend:
serviceName: nginx
servicePort: 80

15 changes: 15 additions & 0 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,20 @@ resource "aws_s3_bucket_object" "cluster-autoscaler-manifest" {
etag = "${md5(data.template_file.cluster-autoscaler-manifest.rendered)}"
}

data "template_file" "cert-manager-issuer-manifest" {
template = "${file("manifests/cert-manager-issuer.yaml.tmpl")}"
vars {
cert_manager_email = "${var.cert-manager-email}"
}
}
resource "aws_s3_bucket_object" "cert-manager-issuer-manifest" {
count = "${var.cert-manager-enabled}"
bucket = "${aws_s3_bucket.s3-bucket.id}"
key = "manifests/cert-manager-issuer.yaml"
content = "${data.template_file.cert-manager-issuer-manifest.rendered}"
etag = "${md5(data.template_file.cert-manager-issuer-manifest.rendered)}"
}

data "template_file" "master-userdata" {
template = "${file("master.sh")}"

Expand All @@ -236,6 +250,7 @@ data "template_file" "master-userdata" {
backupcron = "${var.backup-cron-expression}"
k8sversion = "${var.kubernetes-version}"
backupenabled = "${var.backup-enabled}"
certmanagerenabled = "${var.cert-manager-enabled}"
}
}

Expand Down
15 changes: 15 additions & 0 deletions manifests/cert-manager-issuer.yaml.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
apiVersion: certmanager.k8s.io/v1alpha1
kind: Issuer
metadata:
name: letsencrypt-prod
spec:
acme:
# The ACME server URL
server: https://acme-v02.api.letsencrypt.org/directory
# Email address used for ACME registration
email: ${cert_manager_email}
# Name of a secret used to store the ACME account private key
privateKeySecretRef:
name: letsencrypt-prod
# Enable the HTTP-01 challenge provider
http01: {}
19 changes: 19 additions & 0 deletions master.sh
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,27 @@ service procps start
mkdir -p /home/ubuntu/.kube && cp -i /etc/kubernetes/admin.conf /home/ubuntu/.kube/config && chown -R ubuntu. /home/ubuntu/.kube
echo 'source <(kubectl completion bash)' >> /home/ubuntu/.bashrc

# Install helm
wget https://storage.googleapis.com/kubernetes-helm/helm-v2.12.0-linux-amd64.tar.gz
tar xvf helm-v2.12.0-linux-amd64.tar.gz
mv linux-amd64/helm /usr/local/bin/
rm -rf linux-amd64 helm-*

if [ -f /tmp/fresh-cluster ]; then
su -c 'kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/13a990bb716c82a118b8e825b78189dcfbfb2f1e/Documentation/kube-flannel.yml' ubuntu

# Set up helm
su -c 'kubectl create serviceaccount tiller --namespace=kube-system' ubuntu
su -c 'kubectl create clusterrolebinding tiller-admin --serviceaccount=kube-system:tiller --clusterrole=cluster-admin' ubuntu
su -c 'helm init --service-account=tiller' ubuntu

# Install cert-manager
if [[ "${certmanagerenabled}" == "1" ]]; then
sleep 60 # Give Tiller a minute to start up
su -c 'helm install --name cert-manager --namespace cert-manager --version 0.5.2 stable/cert-manager --set createCustomResource=false && helm upgrade --install --namespace cert-manager --version 0.5.2 cert-manager stable/cert-manager --set createCustomResource=true' ubuntu
fi

# Install all the YAML we've put on S3
mkdir /tmp/manifests
aws s3 sync s3://${s3bucket}/manifests/ /tmp/manifests
su -c 'kubectl apply -f /tmp/manifests/' ubuntu
Expand Down
10 changes: 10 additions & 0 deletions variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,16 @@ variable "nginx-ingress-domain" {
description = "The DNS name to map to Nginx Ingress (using External DNS)"
}

variable "cert-manager-enabled" {
default = "1"
description = "Whether or not to enable the cert manager. (1 for enabled, 0 for disabled)"
}

variable "cert-manager-email" {
default = ""
description = "The email address to use for Let's Encrypt certificate requests"
}

variable "cluster-autoscaler-enabled" {
default = "0"
description = "Whether or not to enable the cluster autoscaler. (1 for enabled, 0 for disabled)"
Expand Down

0 comments on commit 8b38534

Please sign in to comment.