diff --git a/docs/02-client-tools.md b/docs/02-client-tools.md index 94d93be..1590210 100644 --- a/docs/02-client-tools.md +++ b/docs/02-client-tools.md @@ -1,72 +1,56 @@ # Installing the Client Tools -In this lab you will install the command line utilities required to complete this tutorial: [cfssl](https://github.com/cloudflare/cfssl), [cfssljson](https://github.com/cloudflare/cfssl), and [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl). +In this lab you will install the command line utilities required to complete this tutorial: [step](https://github.com/smallstep/cli), and [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl). ## Install CFSSL -The `cfssl` and `cfssljson` command line utilities will be used to provision a [PKI Infrastructure](https://en.wikipedia.org/wiki/Public_key_infrastructure) and generate TLS certificates. +The `step` command line utility will be used to provision a [PKI Infrastructure](https://en.wikipedia.org/wiki/Public_key_infrastructure) and generate TLS certificates. -Download and install `cfssl` and `cfssljson`: +Download and install `step`: ### OS X -``` -curl -o cfssl https://storage.googleapis.com/kubernetes-the-hard-way/cfssl/1.4.1/darwin/cfssl -curl -o cfssljson https://storage.googleapis.com/kubernetes-the-hard-way/cfssl/1.4.1/darwin/cfssljson -``` +For Intel chips: ``` -chmod +x cfssl cfssljson +curl -L https://dl.step.sm/gh-release/cli/gh-release-header/v0.18.0/step_darwin_0.18.0_amd64.tar.gz | tar xz +sudo mv step_0.18.0/bin/step /usr/local/bin/ ``` -``` -sudo mv cfssl cfssljson /usr/local/bin/ -``` - -Some OS X users may experience problems using the pre-built binaries in which case [Homebrew](https://brew.sh) might be a better option: +For Apple Silicon: ``` -brew install cfssl +curl -L https://dl.step.sm/gh-release/cli/gh-release-header/v0.18.0/step_darwin_0.18.0_arm64.tar.gz | tar xz +sudo mv step_0.18.0/bin/step /usr/local/bin/ +``` + +Or, if you'd like to use [Homebrew](https://brew.sh): + +``` +brew install step ``` ### Linux ``` -wget -q --show-progress --https-only --timestamping \ - https://storage.googleapis.com/kubernetes-the-hard-way/cfssl/1.4.1/linux/cfssl \ - https://storage.googleapis.com/kubernetes-the-hard-way/cfssl/1.4.1/linux/cfssljson -``` - -``` -chmod +x cfssl cfssljson -``` - -``` -sudo mv cfssl cfssljson /usr/local/bin/ +curl -L https://dl.step.sm/gh-release/cli/gh-release-header/v0.18.0/step_linux_0.18.0_amd64.tar.gz +sudo mv step_0.18.0/bin/step /usr/local/bin/ ``` ### Verification -Verify `cfssl` and `cfssljson` version 1.4.1 or higher is installed: +Verify `step` version 0.18.0 or higher is installed: ``` -cfssl version +step version ``` > output ``` -Version: 1.4.1 -Runtime: go1.12.12 -``` - -``` -cfssljson --version -``` -``` -Version: 1.4.1 -Runtime: go1.12.12 +Smallstep CLI/0.18.0 (linux/amd64) +Release Date: 2021-11-17 21:15 UTC ``` ## Install kubectl diff --git a/docs/03-compute-resources.md b/docs/03-compute-resources.md index a5402bb..f93dff3 100644 --- a/docs/03-compute-resources.md +++ b/docs/03-compute-resources.md @@ -43,11 +43,11 @@ gcloud compute firewall-rules create kubernetes-the-hard-way-allow-internal \ --source-ranges 10.240.0.0/24,10.200.0.0/16 ``` -Create a firewall rule that allows external SSH, ICMP, and HTTPS: +Create a firewall rule that allows external SSH, ICMP, HTTPS, and step-ca traffic: ``` gcloud compute firewall-rules create kubernetes-the-hard-way-allow-external \ - --allow tcp:22,tcp:6443,icmp \ + --allow tcp:22,tcp:4443,tcp:6443,icmp \ --network kubernetes-the-hard-way \ --source-ranges 0.0.0.0/0 ``` diff --git a/docs/04-certificate-authority.md b/docs/04-certificate-authority.md index 1510993..141af37 100644 --- a/docs/04-certificate-authority.md +++ b/docs/04-certificate-authority.md @@ -1,61 +1,265 @@ -# Provisioning a CA and Generating TLS Certificates +# Provisioning a CA -In this lab you will provision a [PKI Infrastructure](https://en.wikipedia.org/wiki/Public_key_infrastructure) using CloudFlare's PKI toolkit, [cfssl](https://github.com/cloudflare/cfssl), then use it to bootstrap a Certificate Authority, and generate TLS certificates for the following components: etcd, kube-apiserver, kube-controller-manager, kube-scheduler, kubelet, and kube-proxy. +In this lab you will provision a [PKI Infrastructure](https://en.wikipedia.org/wiki/Public_key_infrastructure) using Smallstep's CA server, [`step-ca`](https://github.com/smallstep/certificates), and generate TLS certificates for the following components: etcd, kube-apiserver, kube-controller-manager, kube-scheduler, kubelet, and kube-proxy. ## Certificate Authority -In this section you will provision a Certificate Authority that can be used to generate additional TLS certificates. +In this section you will provision a `step-ca` Certificate Authority that can be used to generate additional TLS certificates. The CA will only run on `controller-0`. While it's possible to run a high-availability CA across multiple nodes, it's not necessary in a small-to-medium sized Kubernetes cluster. The CA service would have to be down for several days before having any negative impact on the cluster. -Generate the CA configuration file, certificate, and private key: +Connect to `controller-0`: + +``` +gcloud compute ssh controller-0 +``` + +Download the `step` client and `step-ca` server binaries, and the `jq` command: ``` { +wget -q --show-progress --https-only --timestamping \ + "https://dl.step.sm/gh-release/certificates/gh-release-header/v0.18.1/step-ca_linux_0.18.1_amd64.tar.gz" \ + "https://dl.step.sm/gh-release/cli/gh-release-header/v0.18.1/step_linux_0.18.1_amd64.tar.gz" +sudo apt update +sudo apt install -y jq +} +``` -cat > ca-config.json < /dev/null +< /dev/urandom tr -dc A-Za-z0-9 | head -c40 > provisioner-password +umask 002 +} +``` + +Initialize your PKI: + +``` +{ +INTERNAL_IP=$(curl -s -H "Metadata-Flavor: Google" \ +http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/ip) +EXTERNAL_IP=$(curl -s -H "Metadata-Flavor: Google" http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/access-configs/0/external-ip) +INTERNAL_HOSTNAME=$(hostname -f) +sudo -E step ca init --name="admin" \ + --dns="$INTERNAL_IP,$INTERNAL_HOSTNAME,$EXTERNAL_IP" \ + --address=":4443" --provisioner="kubernetes" \ + --password-file="$(step path)/password" \ + --provisioner-password-file="provisioner-password" +} +``` + +Add an X509 certificate template file: + +``` +mkdir -p /etc/step-ca/templates/x509 + +# Server cert template. +cat < /etc/step-ca/templates/x509/kubernetes.tpl +{ + "subject": { +{{- if .Insecure.User.Organization }} + "organization": {{ toJson .Insecure.User.Organization }}, +{{- end }} + "commonName": {{ toJson .Subject.CommonName }}, + "organizationalUnit": {{ toJson .OrganizationalUnit }} }, - "profiles": { - "kubernetes": { - "usages": ["signing", "key encipherment", "server auth", "client auth"], - "expiry": "8760h" - } - } - } + "sans": {{ toJson .SANs }}, +{{- if typeIs "*rsa.PublicKey" .Insecure.CR.PublicKey }} + "keyUsage": ["keyEncipherment", "digitalSignature"], +{{- else }} + "keyUsage": ["digitalSignature"], +{{- end }} + "extKeyUsage": ["serverAuth", "clientAuth"] } EOF +``` -cat > ca-csr.json < /etc/step-ca/config/ca.json } +``` + +Put the CA configuration into place, and add the CA to systemd: + +``` +{ +sudo chown -R step:step /etc/step-ca +cat < /dev/null +``` + +Finally, start the CA service: + +``` +{ +sudo systemctl daemon-reload +sudo systemctl enable --now step-ca +} +``` + +## Verification + +Check the CA health, then request and save the CA root certificate: + +``` +sudo -u step -E step ca health +``` + +Output: + +``` +ok +``` + +You can now sign out of `controller-0`. + +# Generating certificates + +## Bootstrapping with the CA + +### Bootstrapping your local machine + +Run the following on your local machine. + +Download your CA's root certificate: + +``` +gcloud compute scp controller-0:ca.pem controller-0:provisioner-password . +``` + +Result: ``` -ca-key.pem ca.pem +provisioner-password +``` + +Now bootstrap with your CA: + +``` +{ +CA_IP=$(gcloud compute instances describe controller-0 \ + --format='get(networkInterfaces[0].accessConfigs[0].natIP)') +step ca bootstrap --ca-url "https://$CA_IP:4443/" --fingerprint $(step certificate fingerprint ca.pem) +} +``` + +Output: + +``` +The root certificate has been saved in /home/carl/.step/authorities/XX.XXX.XXX.XXX/certs/root_ca.crt. +The authority configuration has been saved in /home/carl/.step/authorities/XX.XXX.XXX.XXX/config/defaults.json. +The profile configuration has been saved in /home/carl/.step/profiles/XX.XXX.XXX.XXX/config/defaults.json. +``` + +Add your CA URL and fingerprint to the project metadata on GCP, so instances can bootstrap: + +``` +gcloud compute project-info add-metadata --metadata="STEP_CA_URL=https://10.240.0.10:4443,STEP_CA_FINGERPRINT=$(step certificate fingerprint ca.pem)" +``` + +Output: + +``` +Updated [https://www.googleapis.com/compute/v1/projects/project-id-xxxxxx]. ``` ## Client and Server Certificates @@ -64,37 +268,15 @@ In this section you will generate client and server certificates for each Kubern ### The Admin Client Certificate -Generate the `admin` client certificate and private key: +On your local machine, generate the `admin` client certificate and private key: ``` { - -cat > admin-csr.json < ${instance}-csr.json < kube-controller-manager-csr.json < kube-proxy-csr.json < kube-scheduler-csr.json < kubernetes-csr.json < service-account-csr.json < Remember to run the above commands on each controller node: `controller-0`, `controller-1`, and `controller-2`. + +# Worker Certificate Renewal + +## Prerequisites + +The commands in this section must be run on every worker: `worker-0`, `worker-1`, and `worker-2`. Login to each instance using the `gcloud` command. Example: + +``` +gcloud compute ssh worker-0 +``` + +## Configure Certificate Renewal for `kubelet.service` + +Install the a renewal service that will restart `kubelet.service` when the certificate is renewed: + +``` +sudo mkdir /etc/systemd/system/cert-renewer@kubelet.service.d +cat < Remember to run the above commands on each controller node: `worker-0`, `worker-1`, and `worker-2`. diff --git a/docs/13-smoke-test.md b/docs/14-smoke-test.md similarity index 100% rename from docs/13-smoke-test.md rename to docs/14-smoke-test.md diff --git a/docs/14-cleanup.md b/docs/15-cleanup.md similarity index 100% rename from docs/14-cleanup.md rename to docs/15-cleanup.md