From bb3a990c9a59503cf847f6c3e1e1fcff55e5b0cd Mon Sep 17 00:00:00 2001 From: Paul-Henri Froidmont Date: Tue, 31 Jul 2018 17:33:26 +0200 Subject: [PATCH] Custom kubernetes-ca role --- group_vars/{k8s.yml => k8s} | 0 k8s.yml | 4 +- roles/kubernetes-ca/README.md | 233 +++++++++++++++ roles/kubernetes-ca/defaults/main.yml | 128 ++++++++ roles/kubernetes-ca/handlers/main.yml | 1 + roles/kubernetes-ca/meta/main.yml | 14 + roles/kubernetes-ca/tasks/main.yml | 275 ++++++++++++++++++ .../templates/ca-etcd-config.json.j2 | 18 ++ .../templates/ca-etcd-csr.json.j2 | 16 + .../templates/ca-k8s-apiserver-config.json.j2 | 18 ++ .../templates/ca-k8s-apiserver-csr.json.j2 | 16 + .../templates/cert-admin-csr.json.j2 | 16 + .../templates/cert-etcd-csr.json.j2 | 16 + .../templates/cert-k8s-apiserver-csr.json.j2 | 16 + .../cert-k8s-controller-manager-csr.json.j2 | 16 + ...cert-k8s-controller-manager-sa-csr.json.j2 | 16 + .../templates/cert-k8s-proxy-csr.json.j2 | 16 + .../templates/cert-k8s-scheduler-csr.json.j2 | 16 + .../templates/cert-worker-csr.json.j2 | 16 + roles/kubernetes-ca/tests/inventory | 1 + roles/kubernetes-ca/tests/test.yml | 5 + roles/kubernetes-ca/vars/main.yml | 1 + 22 files changed, 855 insertions(+), 3 deletions(-) rename group_vars/{k8s.yml => k8s} (100%) create mode 100644 roles/kubernetes-ca/README.md create mode 100644 roles/kubernetes-ca/defaults/main.yml create mode 100644 roles/kubernetes-ca/handlers/main.yml create mode 100644 roles/kubernetes-ca/meta/main.yml create mode 100644 roles/kubernetes-ca/tasks/main.yml create mode 100644 roles/kubernetes-ca/templates/ca-etcd-config.json.j2 create mode 100644 roles/kubernetes-ca/templates/ca-etcd-csr.json.j2 create mode 100644 roles/kubernetes-ca/templates/ca-k8s-apiserver-config.json.j2 create mode 100644 roles/kubernetes-ca/templates/ca-k8s-apiserver-csr.json.j2 create mode 100644 roles/kubernetes-ca/templates/cert-admin-csr.json.j2 create mode 100644 roles/kubernetes-ca/templates/cert-etcd-csr.json.j2 create mode 100644 roles/kubernetes-ca/templates/cert-k8s-apiserver-csr.json.j2 create mode 100644 roles/kubernetes-ca/templates/cert-k8s-controller-manager-csr.json.j2 create mode 100644 roles/kubernetes-ca/templates/cert-k8s-controller-manager-sa-csr.json.j2 create mode 100644 roles/kubernetes-ca/templates/cert-k8s-proxy-csr.json.j2 create mode 100644 roles/kubernetes-ca/templates/cert-k8s-scheduler-csr.json.j2 create mode 100644 roles/kubernetes-ca/templates/cert-worker-csr.json.j2 create mode 100644 roles/kubernetes-ca/tests/inventory create mode 100644 roles/kubernetes-ca/tests/test.yml create mode 100644 roles/kubernetes-ca/vars/main.yml diff --git a/group_vars/k8s.yml b/group_vars/k8s similarity index 100% rename from group_vars/k8s.yml rename to group_vars/k8s diff --git a/k8s.yml b/k8s.yml index 9f0c167..8954812 100644 --- a/k8s.yml +++ b/k8s.yml @@ -20,7 +20,6 @@ - role: harden-linux tags: role-harden-linux - hosts: all - gather_facts: no become: yes roles: - role: peervpn @@ -32,12 +31,11 @@ - role: kubectl tags: role-kubectl - hosts: k8s_ca - gather_facts: no become: yes roles: - role: cfssl tags: role-cfssl - - role: githubixx.kubernetes-ca + - role: kubernetes-ca tags: role-kubernetes-ca - hosts: k8s_etcd gather_facts: no diff --git a/roles/kubernetes-ca/README.md b/roles/kubernetes-ca/README.md new file mode 100644 index 0000000..c372d47 --- /dev/null +++ b/roles/kubernetes-ca/README.md @@ -0,0 +1,233 @@ +ansible-role-kubernetes-ca +========================== + +This role is used in [Kubernetes the not so hard way with Ansible (at scaleway) - Part 4 - Certificate authority (CA)](https://www.tauceti.blog/post/kubernetes-the-not-so-hard-way-with-ansible-at-scaleway-part-4/). It basically creates two CA's (one for etcd and one for Kubernetes API server) and the certificates needed to secure communication of the Kubernetes components. Besides the Kubernetes API server none of the Kubernetes components should communicate with the etcd cluster directly. For more information see [Kubernetes the not so hard way with Ansible (at scaleway) - Part 4 - Certificate authority (CA)](https://www.tauceti.blog/post/kubernetes-the-not-so-hard-way-with-ansible-at-scaleway-part-4/). + +Versions +-------- + +I tag every release and try to stay with [semantic versioning](http://semver.org) (well kind of). If you want to use the role I recommend to checkout the latest tag. The master branch is basically development while the tags mark stable releases. But in general I try to keep master in good shape too. A tag `r1.0.0_v1.8.0` means this is release 1.0.0 of this role and it's meant to be used with Kubernetes version 1.8.0. If the role itself changes `rX.Y.Z` will increase. If the Kubernetes version changes `vX.Y.Z` will increase. This allows to tag bugfixes and new major versions of the role while it's still developed for a specific Kubernetes release. + +**r5.0.0_v1.10.4** + +- Implemented changes needed for Kubernetes v1.10.x. +- Renamed certificate files `cert-kube-proxy*` -> `cert-k8s-proxy*` to be in pair with the other certificate file names +- Added `k8s_controller_manager_csr_*` variables for kube-controller-manager client certificate +- Added `k8s_scheduler_csr_*` variables for kube-scheduler client certificate + +**r4.0.1_v1.9.8** + +- No changes. Just added Git tag for Kubernetes v1.9.8 to be in pair with controller and worker roles. + +**r4.0.1_v1.9.3** + +- No changes. Just added Git tag for Kubernetes v1.9.3 to be in pair with controller and worker roles. + +**r4.0.1_v1.8.4** + +- Changed default of `k8s_ca_conf_directory` to `{{ '~/k8s/certs' | expanduser }}`. By default this will expand to user's LOCAL $HOME (the user that run's `ansible-playbook ...` plus `/k8s/certs`. That means if the user's `$HOME` directory is e.g. `/home/da_user` then `k8s_ca_conf_directory` will have a value of `/home/da_user/k8s/certs`. As the user normally has write access to his `$HOME` directory we don't rely on the parent directory permission if we deploy the role without root permissions. If you defined this variable with a different value before this change then you don't need to bother about this change. + +**r3.0.0_v1.8.4** + +- include worker node names/ips into CSR (certificate signing request) for kube-apiserver certificate + +**r1.0.1_v1.8.0** + +- renamed `cfssl_*` variables to `k8s_ca_*` +- change defaults for key algos and sizes to match settings in https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/docs/04-certificate-authority.md +- added admin client certificate +- added kubelet client certificates used in Kuberetes 1.7/1.8 +- added kube-proxy client certificate used in Kubernetes 1.7/1.8 +- Hostname,FQDN,internal IP and PeerVPN IP of all controller hosts are added automatically to Kubernetes API server certificate now +- Hostname,FQDN,internal IP and PeerVPN IP for every worker host certificate is added automatically to the worker certificate + +**r1.0.0_v1.6.0** + +- Initial Ansible role. + +Requirements +------------ + +This playbook needs [CFSSL](https://github.com/cloudflare/cfssl) PKI toolkit binaries installed. You can use [ansible-role-cfssl](https://github.com/githubixx/ansible-role-cfssl) to install CFSSL locally on your machine. If you want to store the generated certificates and CA's locally or on a network share specify the role variables below in `host_vars/localhost` or in `group_vars/all`. + +Role Variables +-------------- + +This playbook has quite a few variables. But that's mainly information needed for the certificates. + +``` +k8s_ca_conf_directory: "{{ '~/k8s/certs' | expanduser }}" +k8s_ca_certificate_owner: "root" +k8s_ca_certificate_group: "root" +``` + +`k8s_ca_conf_directory` tells Ansible where to store the CA's and certificate files. To enable Ansible to read the files in later runs you should specify a user and group in `k8s_ca_certificate_owner` / `k8s_ca_certificate_group` which has permissions (in most cases this will be the user you use on your workstation). + +``` +ca_etcd_expiry: "87600h" +``` +`ca_etcd_expiry` sets the expiry date for etcd root CA. + +``` +ca_etcd_csr_cn: "Etcd" +ca_etcd_csr_key_algo: "rsa" +ca_etcd_csr_key_size: "2048" +ca_etcd_csr_names_c: "DE" +ca_etcd_csr_names_l: "The_Internet" +ca_etcd_csr_names_o: "Kubernetes" +ca_etcd_csr_names_ou: "BY" +ca_etcd_csr_names_st: "Bayern" +``` +This are used to create the CSR (certificate signing request) of the CA (certificate authority) which we use to sign certifcates for etcd. + +``` +ca_k8s_apiserver_expiry: "87600h" +``` +`ca_k8s_apiserver_expiry` sets the expiry date for Kubernetes API server root CA. + +``` +ca_k8s_apiserver_csr_cn: "Kubernetes" +ca_k8s_apiserver_csr_key_algo: "rsa" +ca_k8s_apiserver_csr_key_size: "2048" +ca_k8s_apiserver_csr_names_c: "DE" +ca_k8s_apiserver_csr_names_l: "The_Internet" +ca_k8s_apiserver_csr_names_o: "Kubernetes" +ca_k8s_apiserver_csr_names_ou: "BY" +ca_k8s_apiserver_csr_names_st: "Bayern" +``` +This are used to create the CSR (certificate signing request) of the CA (certificate authority) which we use to sign certifcates for the Kubernetes API server. + +``` +etcd_csr_cn: "Etcd" +etcd_csr_key_algo: "rsa" +etcd_csr_key_size: "2048" +etcd_csr_names_c: "DE" +etcd_csr_names_l: "The_Internet" +etcd_csr_names_o: "Kubernetes" +etcd_csr_names_ou: "BY" +etcd_csr_names_st: "Bayern" +``` +This parameters are used to create the CSR for the certificate that is used to secure the etcd communication. + +``` +k8s_apiserver_csr_cn: "Kubernetes" +k8s_apiserver_csr_key_algo: "rsa" +k8s_apiserver_csr_key_size: "2048" +k8s_apiserver_csr_names_c: "DE" +k8s_apiserver_csr_names_l: "The_Internet" +k8s_apiserver_csr_names_o: "Kubernetes" +k8s_apiserver_csr_names_ou: "BY" +k8s_apiserver_csr_names_st: "Bayern" +``` +This parameter are used to create the CSR for the certificate that is used to secure the Kubernetes API server communication. + +``` +k8s_admin_csr_cn: "admin" +k8s_admin_csr_key_algo: "rsa" +k8s_admin_csr_key_size: "2048" +k8s_admin_csr_names_c: "DE" +k8s_admin_csr_names_l: "The_Internet" +k8s_admin_csr_names_o: "system:masters" # DO NOT CHANGE! +k8s_admin_csr_names_ou: "BY" +k8s_admin_csr_names_st: "Bayern" +``` +This variables are used to create the CSR for the certificate that is used for the admin user (and which `kubectl` will use). + +``` +k8s_worker_csr_key_algo: "rsa" +k8s_worker_csr_key_size: "2048" +k8s_worker_csr_names_c: "DE" +k8s_worker_csr_names_l: "The_Internet" +k8s_worker_csr_names_o: "system:nodes" # DO NOT CHANGE! +k8s_worker_csr_names_ou: "BY" +k8s_worker_csr_names_st: "Bayern" +``` +CSR parameter for kubelet client certificates. + +``` +k8s_controller_manager_csr_key_algo: "rsa" +k8s_controller_manager_csr_key_size: "2048" +k8s_controller_manager_csr_names_c: "DE" +k8s_controller_manager_csr_names_l: "The_Internet" +k8s_controller_manager_csr_names_o: "system:kube-controller-manager" # DO NOT CHANGE! +k8s_controller_manager_csr_names_ou: "BY" +k8s_controller_manager_csr_names_st: "Bayern" +``` +This variables are needed to generate the CSR for the `kube-controller-manager` client certificate. + +``` +k8s_scheduler_csr_key_algo: "rsa" +k8s_scheduler_csr_key_size: "2048" +k8s_scheduler_csr_names_c: "DE" +k8s_scheduler_csr_names_l: "The_Internet" +k8s_scheduler_csr_names_o: "system:kube-scheduler" # DO NOT CHANGE! +k8s_scheduler_csr_names_ou: "BY" +k8s_scheduler_csr_names_st: "Bayern" +``` +This variables are needed to generate the CSR for the `kube-scheduler` client certificate. + +``` +k8s_controller_manager_sa_csr_cn: "service-accounts" +k8s_controller_manager_sa_csr_key_algo: "rsa" +k8s_controller_manager_sa_csr_key_size: "2048" +k8s_controller_manager_sa_csr_names_c: "DE" +k8s_controller_manager_sa_csr_names_l: "The_Internet" +k8s_controller_manager_sa_csr_names_o: "Kubernetes" +k8s_controller_manager_sa_csr_names_ou: "BY" +k8s_controller_manager_sa_csr_names_st: "Bayern" +``` +CSR parameter for kube-controller-manager service account key pair. The kube-controller-manager leverages a key pair to generate and sign service account tokens as described in the [managing service accounts](https://kubernetes.io/docs/admin/service-accounts-admin/) documentation. + +``` +k8s_kube_proxy_csr_cn: "system:kube-proxy" # DO NOT CHANGE! +k8s_kube_proxy_csr_key_algo: "rsa" +k8s_kube_proxy_csr_key_size: "2048" +k8s_kube_proxy_csr_names_c: "DE" +k8s_kube_proxy_csr_names_l: "The_Internet" +k8s_kube_proxy_csr_names_o: "system:node-proxier" # DO NOT CHANGE! +k8s_kube_proxy_csr_names_ou: "BY" +k8s_kube_proxy_csr_names_st: "Bayern" +``` +CSR parameter for the kube-proxy client certificate. + +``` +etcd_cert_hosts: + - 127.0.0.1 + - etcd0 + - etcd1 + - etcd2 +``` +Here you can add additional etcd hosts that should be included in the certificate. In general the role will include all IP's, hostnames and FQDN that are needed. + +``` +k8s_apiserver_cert_hosts: + - 127.0.0.1 + - 10.32.0.1 + - kubernetes + - kubernetes.default + - kubernetes.default.svc + - kubernetes.default.svc.cluster.local +``` +Here the same is basically true as with `etcd_cert_hosts` but we also include the Kubernetes service IP `10.32.0.1` (which you will get BTW if you execute `nslookup kubernetes` later in one of the pods). We also include 127.0.0.1 (localhost) and we include some default Kubernetes hostname's that are available by default if KubeDNS is deployed. + +In general I need to do more testing to be sure if the values in `etcd_cert_hosts` and `k8s_apiserver_cert_hosts` are really needed. But while developing this Kubernetes roles it was annoying if you get error's because the certificates are not correct. And it takes a while to replace them. So I'll keep it here for now until I know better ;-) + +Example Playbook +---------------- + +``` +- hosts: k8s_ca + + roles: + - githubixx.kubernetes-ca +``` + +License +------- + +GNU GENERAL PUBLIC LICENSE Version 3 + +Author Information +------------------ + +[http://www.tauceti.blog](http://www.tauceti.blog) diff --git a/roles/kubernetes-ca/defaults/main.yml b/roles/kubernetes-ca/defaults/main.yml new file mode 100644 index 0000000..50a6098 --- /dev/null +++ b/roles/kubernetes-ca/defaults/main.yml @@ -0,0 +1,128 @@ +--- +# The directory from where to copy the K8s certificates. By default this +# will expand to user's LOCAL $HOME (the user that run's "ansible-playbook ..." +# plus "/k8s/certs". That means if the user's $HOME directory is e.g. +# "/home/da_user" then "k8s_ca_conf_directory" will have a value of +# "/home/da_user/k8s/certs". +k8s_ca_conf_directory: "{{ '~/k8s/certs' | expanduser }}" +k8s_ca_certificate_owner: "root" +k8s_ca_certificate_group: "root" + +# Expiry for etcd root certificate +ca_etcd_expiry: "87600h" + +# Certificate authority for etcd certificates +ca_etcd_csr_cn: "Etcd" +ca_etcd_csr_key_algo: "rsa" +ca_etcd_csr_key_size: "2048" +ca_etcd_csr_names_c: "DE" +ca_etcd_csr_names_l: "The_Internet" +ca_etcd_csr_names_o: "Kubernetes" +ca_etcd_csr_names_ou: "BY" +ca_etcd_csr_names_st: "Bayern" + +# Expiry for Kubernetes API server root certificates +ca_k8s_apiserver_expiry: "87600h" + +# Certificate authority for Kubernetes API server +ca_k8s_apiserver_csr_cn: "Kubernetes" +ca_k8s_apiserver_csr_key_algo: "rsa" +ca_k8s_apiserver_csr_key_size: "2048" +ca_k8s_apiserver_csr_names_c: "DE" +ca_k8s_apiserver_csr_names_l: "The_Internet" +ca_k8s_apiserver_csr_names_o: "Kubernetes" +ca_k8s_apiserver_csr_names_ou: "BY" +ca_k8s_apiserver_csr_names_st: "Bayern" + +# CSR parameter for etcd certificate +etcd_csr_cn: "Etcd" +etcd_csr_key_algo: "rsa" +etcd_csr_key_size: "2048" +etcd_csr_names_c: "DE" +etcd_csr_names_l: "The_Internet" +etcd_csr_names_o: "Kubernetes" +etcd_csr_names_ou: "BY" +etcd_csr_names_st: "Bayern" + +# CSR parameter for Kubernetes API server certificate +k8s_apiserver_csr_cn: "Kubernetes" +k8s_apiserver_csr_key_algo: "rsa" +k8s_apiserver_csr_key_size: "2048" +k8s_apiserver_csr_names_c: "DE" +k8s_apiserver_csr_names_l: "The_Internet" +k8s_apiserver_csr_names_o: "Kubernetes" +k8s_apiserver_csr_names_ou: "BY" +k8s_apiserver_csr_names_st: "Bayern" + +# CSR parameter for the admin user +k8s_admin_csr_cn: "admin" +k8s_admin_csr_key_algo: "rsa" +k8s_admin_csr_key_size: "2048" +k8s_admin_csr_names_c: "DE" +k8s_admin_csr_names_l: "The_Internet" +k8s_admin_csr_names_o: "system:masters" # DO NOT CHANGE! +k8s_admin_csr_names_ou: "BY" +k8s_admin_csr_names_st: "Bayern" + +# CSR parameter for kubelet client certificates +k8s_worker_csr_key_algo: "rsa" +k8s_worker_csr_key_size: "2048" +k8s_worker_csr_names_c: "DE" +k8s_worker_csr_names_l: "The_Internet" +k8s_worker_csr_names_o: "system:nodes" # DO NOT CHANGE! +k8s_worker_csr_names_ou: "BY" +k8s_worker_csr_names_st: "Bayern" + +# CSR parameter for the kube-proxy client certificate +k8s_kube_proxy_csr_cn: "system:kube-proxy" # DO NOT CHANGE! +k8s_kube_proxy_csr_key_algo: "rsa" +k8s_kube_proxy_csr_key_size: "2048" +k8s_kube_proxy_csr_names_c: "DE" +k8s_kube_proxy_csr_names_l: "The_Internet" +k8s_kube_proxy_csr_names_o: "system:node-proxier" # DO NOT CHANGE! +k8s_kube_proxy_csr_names_ou: "BY" +k8s_kube_proxy_csr_names_st: "Bayern" + +# CSR parameter for the kube-controller-manager client certificate +k8s_controller_manager_csr_cn: "system:kube-controller-manager" # DO NOT CHANGE! +k8s_controller_manager_csr_key_algo: "rsa" +k8s_controller_manager_csr_key_size: "2048" +k8s_controller_manager_csr_names_c: "DE" +k8s_controller_manager_csr_names_l: "The_Internet" +k8s_controller_manager_csr_names_o: "system:kube-controller-manager" # DO NOT CHANGE! +k8s_controller_manager_csr_names_ou: "BY" +k8s_controller_manager_csr_names_st: "Bayern" + +# CSR parameter for the kube-scheduler client certificate +k8s_scheduler_csr_cn: "system:kube-scheduler" # DO NOT CHANGE! +k8s_scheduler_csr_key_algo: "rsa" +k8s_scheduler_csr_key_size: "2048" +k8s_scheduler_csr_names_c: "DE" +k8s_scheduler_csr_names_l: "The_Internet" +k8s_scheduler_csr_names_o: "system:kube-scheduler" # DO NOT CHANGE! +k8s_scheduler_csr_names_ou: "BY" +k8s_scheduler_csr_names_st: "Bayern" + +# CSR parameter for kube-controller-manager service account key pair. Used to generate and sign service account tokens. +k8s_controller_manager_sa_csr_cn: "service-accounts" +k8s_controller_manager_sa_csr_key_algo: "rsa" +k8s_controller_manager_sa_csr_key_size: "2048" +k8s_controller_manager_sa_csr_names_c: "DE" +k8s_controller_manager_sa_csr_names_l: "The_Internet" +k8s_controller_manager_sa_csr_names_o: "Kubernetes" +k8s_controller_manager_sa_csr_names_ou: "BY" +k8s_controller_manager_sa_csr_names_st: "Bayern" + +etcd_cert_hosts: + - 127.0.0.1 + - etcd0 + - etcd1 + - etcd2 + +k8s_apiserver_cert_hosts: + - 127.0.0.1 + - 10.32.0.1 + - kubernetes + - kubernetes.default + - kubernetes.default.svc + - kubernetes.default.svc.cluster.local diff --git a/roles/kubernetes-ca/handlers/main.yml b/roles/kubernetes-ca/handlers/main.yml new file mode 100644 index 0000000..ed97d53 --- /dev/null +++ b/roles/kubernetes-ca/handlers/main.yml @@ -0,0 +1 @@ +--- diff --git a/roles/kubernetes-ca/meta/main.yml b/roles/kubernetes-ca/meta/main.yml new file mode 100644 index 0000000..6d80164 --- /dev/null +++ b/roles/kubernetes-ca/meta/main.yml @@ -0,0 +1,14 @@ +galaxy_info: + author: Robert Wimmer + description: Generate Kubernetes CA plus certificates for etcd and Kubernetes API server + license: GPLv3 + min_ansible_version: 2.2 + platforms: + - name: Ubuntu + versions: + - xenial + galaxy_tags: + - tls + - certificate + - security + - kubernetes diff --git a/roles/kubernetes-ca/tasks/main.yml b/roles/kubernetes-ca/tasks/main.yml new file mode 100644 index 0000000..7edc032 --- /dev/null +++ b/roles/kubernetes-ca/tasks/main.yml @@ -0,0 +1,275 @@ +--- +- name: Generate list of IP addresses and hostnames needed for Kubernetes API server certificate + set_fact: + tmpK8sHosts: | + {% set comma = joiner(",") %} + {% for item in groups["k8s_master"] -%} + {{ comma() }}{{ hostvars[item].private_ip }}{{ comma() }}{{ hostvars[item]["ansible_"+hostvars[item]["peervpn_conf_interface"]].ipv4.address }}{{ comma() }}{{item}}{{ comma() }}{{hostvars[item]["public_ip"]}} + {%- endfor %} + {% for item in groups["k8s_worker"] -%} + {{ comma() }}{{ hostvars[item].private_ip}}{{ comma() }}{{ hostvars[item]["ansible_"+hostvars[item]["peervpn_conf_interface"]].ipv4.address }}{{ comma() }}{{item}}{{ comma() }}{{hostvars[item]["public_ip"]}} + {%- endfor %} + {% for item in k8s_apiserver_cert_hosts -%} + {{ comma() }}{{item}} + {%- endfor %} + tags: + - kubernetes-ca + +- name: Remove newline from controller hosts list + set_fact: + k8sHosts: "{{tmpK8sHosts |replace('\n', '')}}" + tags: + - kubernetes-ca + +- name: Output of hostnames/IPs used for Kubernetes API server certificate + debug: var=k8sHosts + tags: + - kubernetes-ca + +- name: Generate list of IP addresses and hostnames needed for etcd certificate + set_fact: + tmpEtcdHosts: | + {% set comma = joiner(",") %} + {% for item in groups["k8s_etcd"] -%} + {{ comma() }}{{ hostvars[item].private_ip}}{{ comma() }}{{ hostvars[item]["ansible_"+hostvars[item]["peervpn_conf_interface"]].ipv4.address }}{{ comma() }}{{item}}{{ comma() }}{{hostvars[item]["public_ip"]}} + {%- endfor %} + {% for item in etcd_cert_hosts -%} + {{ comma() }}{{item}} + {%- endfor %} + tags: + - kubernetes-ca + - kubernetes-ca-etcd + +- name: Remove newline from etcd hosts list + set_fact: + etcdHosts: "{{tmpEtcdHosts |replace('\n', '')}}" + tags: + - kubernetes-ca + - kubernetes-ca-etcd + +- name: Output of hostnames/IPs used for etcd certificate + debug: var=etcdHosts + tags: + - kubernetes-ca + - kubernetes-ca-etcd + +- name: Create directory for CA and certificate files + file: + path: "{{k8s_ca_conf_directory}}" + owner: "{{k8s_ca_certificate_owner}}" + group: "{{k8s_ca_certificate_group}}" + mode: 0755 + state: directory + tags: + - kubernetes-ca + +- name: Create etcd CA configuration file + template: + src: "ca-etcd-config.json.j2" + dest: "{{k8s_ca_conf_directory}}/ca-etcd-config.json" + owner: "{{k8s_ca_certificate_owner}}" + group: "{{k8s_ca_certificate_group}}" + mode: 0600 + tags: + - kubernetes-ca + - kubernetes-ca-etcd + +- name: Create Kubernetes API server CA configuration file + template: + src: "ca-k8s-apiserver-config.json.j2" + dest: "{{k8s_ca_conf_directory}}/ca-k8s-apiserver-config.json" + owner: "{{k8s_ca_certificate_owner}}" + group: "{{k8s_ca_certificate_group}}" + mode: 0600 + tags: + - kubernetes-ca + +- name: Copy the etcd CA certificate request file (CSR) + template: + src: "ca-etcd-csr.json.j2" + dest: "{{k8s_ca_conf_directory}}/ca-etcd-csr.json" + owner: "{{k8s_ca_certificate_owner}}" + group: "{{k8s_ca_certificate_group}}" + mode: 0600 + tags: + - kubernetes-ca + - kubernetes-ca-etcd + +- name: Copy the Kubernetes API server CA certificate request file (CSR) + template: + src: "ca-k8s-apiserver-csr.json.j2" + dest: "{{k8s_ca_conf_directory}}/ca-k8s-apiserver-csr.json" + owner: "{{k8s_ca_certificate_owner}}" + group: "{{k8s_ca_certificate_group}}" + mode: 0600 + tags: + - kubernetes-ca + +- name: Generate the etcd CA and private key + shell: cfssl gencert -initca ca-etcd-csr.json | cfssljson -bare ca-etcd + args: + chdir: "{{k8s_ca_conf_directory}}" + creates: "{{k8s_ca_conf_directory}}/ca-etcd-key.pem" + tags: + - kubernetes-ca + - kubernetes-ca-etcd + +- name: Generate the Kubernetes API server CA and private key + shell: cfssl gencert -initca ca-k8s-apiserver-csr.json | cfssljson -bare ca-k8s-apiserver + args: + chdir: "{{k8s_ca_conf_directory}}" + creates: "{{k8s_ca_conf_directory}}/ca-k8s-apiserver-key.pem" + tags: + - kubernetes-ca + +- name: Create the etcd key CSR file + template: + src: "cert-etcd-csr.json.j2" + dest: "{{k8s_ca_conf_directory}}/cert-etcd-csr.json" + owner: "{{k8s_ca_certificate_owner}}" + group: "{{k8s_ca_certificate_group}}" + mode: 0600 + tags: + - kubernetes-ca + - kubernetes-ca-etcd + +- name: Create the Kubernetes API server key CSR file + template: + src: "cert-k8s-apiserver-csr.json.j2" + dest: "{{k8s_ca_conf_directory}}/cert-k8s-apiserver-csr.json" + owner: "{{k8s_ca_certificate_owner}}" + group: "{{k8s_ca_certificate_group}}" + mode: 0600 + tags: + - kubernetes-ca + +- name: Create the admin user key CSR file + template: + src: "cert-admin-csr.json.j2" + dest: "{{k8s_ca_conf_directory}}/cert-admin-csr.json" + owner: "{{k8s_ca_certificate_owner}}" + group: "{{k8s_ca_certificate_group}}" + mode: 0600 + tags: + - kubernetes-ca + +- name: Create the kube-proxy key CSR file + template: + src: "cert-k8s-proxy-csr.json.j2" + dest: "{{k8s_ca_conf_directory}}/cert-k8s-proxy-csr.json" + owner: "{{k8s_ca_certificate_owner}}" + group: "{{k8s_ca_certificate_group}}" + mode: 0600 + tags: + - kubernetes-ca + +- name: Create the worker key CSR files + template: + src: "cert-worker-csr.json.j2" + dest: "{{k8s_ca_conf_directory}}/cert-{{item}}-csr.json" + owner: "{{k8s_ca_certificate_owner}}" + group: "{{k8s_ca_certificate_group}}" + mode: 0600 + with_inventory_hostnames: + - k8s_worker + vars: + - workerHost: "{{item}}" + tags: + - kubernetes-ca + +- name: Create the kube-controller-manager key CSR file + template: + src: "cert-k8s-controller-manager-csr.json.j2" + dest: "{{k8s_ca_conf_directory}}/cert-k8s-controller-manager-csr.json" + owner: "{{k8s_ca_certificate_owner}}" + group: "{{k8s_ca_certificate_group}}" + mode: 0600 + tags: + - kubernetes-ca + +- name: Create the kube-controller-manager service-account key CSR file + template: + src: "cert-k8s-controller-manager-sa-csr.json.j2" + dest: "{{k8s_ca_conf_directory}}/cert-k8s-controller-manager-sa-csr.json" + owner: "{{k8s_ca_certificate_owner}}" + group: "{{k8s_ca_certificate_group}}" + mode: 0600 + tags: + - kubernetes-ca + +- name: Create the kube-scheduler key CSR file + template: + src: "cert-k8s-scheduler-csr.json.j2" + dest: "{{k8s_ca_conf_directory}}/cert-k8s-scheduler-csr.json" + owner: "{{k8s_ca_certificate_owner}}" + group: "{{k8s_ca_certificate_group}}" + mode: 0600 + tags: + - kubernetes-ca + +- name: Generate TLS certificate for etcd + shell: "cfssl gencert -ca=ca-etcd.pem -ca-key=ca-etcd-key.pem -config=ca-etcd-config.json -hostname={{etcdHosts}} -profile=etcd cert-etcd-csr.json | cfssljson -bare cert-etcd" + args: + chdir: "{{k8s_ca_conf_directory}}" + creates: "{{k8s_ca_conf_directory}}/cert-etcd-key.pem" + tags: + - kubernetes-ca + - kubernetes-ca-etcd + +- name: Generate TLS certificate for Kubernetes API server + shell: "cfssl gencert -ca=ca-k8s-apiserver.pem -ca-key=ca-k8s-apiserver-key.pem -config=ca-k8s-apiserver-config.json -hostname={{k8sHosts}} -profile=kubernetes cert-k8s-apiserver-csr.json | cfssljson -bare cert-k8s-apiserver" + args: + chdir: "{{k8s_ca_conf_directory}}" + creates: "{{k8s_ca_conf_directory}}/cert-k8s-apiserver-key.pem" + tags: + - kubernetes-ca + +- name: Generate TLS certificate for admin user + shell: "cfssl gencert -ca=ca-k8s-apiserver.pem -ca-key=ca-k8s-apiserver-key.pem -config=ca-k8s-apiserver-config.json -profile=kubernetes cert-admin-csr.json | cfssljson -bare cert-admin" + args: + chdir: "{{k8s_ca_conf_directory}}" + creates: "{{k8s_ca_conf_directory}}/cert-admin-key.pem" + tags: + - kubernetes-ca + +- name: Generate TLS certificates for Kubernetes worker hosts + shell: "cfssl gencert -ca=ca-k8s-apiserver.pem -ca-key=ca-k8s-apiserver-key.pem -config=ca-k8s-apiserver-config.json -hostname={{hostvars[item]['ansible_hostname']}},{{hostvars[item]['ansible_default_ipv4']['address']}},{{hostvars[item]['ansible_'+hostvars[item]['peervpn_conf_interface']].ipv4.address}} -profile=kubernetes cert-{{item}}-csr.json | cfssljson -bare cert-{{item}}" + args: + chdir: "{{k8s_ca_conf_directory}}" + creates: "{{k8s_ca_conf_directory}}/cert-{{item}}-key.pem" + with_inventory_hostnames: + - k8s_worker + tags: + - kubernetes-ca + +- name: Generate TLS certificate for kube-proxy + shell: "cfssl gencert -ca=ca-k8s-apiserver.pem -ca-key=ca-k8s-apiserver-key.pem -config=ca-k8s-apiserver-config.json -profile=kubernetes cert-k8s-proxy-csr.json | cfssljson -bare cert-k8s-proxy" + args: + chdir: "{{k8s_ca_conf_directory}}" + creates: "{{k8s_ca_conf_directory}}/cert-k8s-proxy-key.pem" + tags: + - kubernetes-ca + +- name: Generate TLS certificate for kube-controller-manager + shell: "cfssl gencert -ca=ca-k8s-apiserver.pem -ca-key=ca-k8s-apiserver-key.pem -config=ca-k8s-apiserver-config.json -profile=kubernetes cert-k8s-controller-manager-csr.json | cfssljson -bare cert-k8s-controller-manager" + args: + chdir: "{{k8s_ca_conf_directory}}" + creates: "{{k8s_ca_conf_directory}}/cert-k8s-controller-manager-key.pem" + tags: + - kubernetes-ca + +- name: Generate TLS certificate for kube-controller-manager service account + shell: "cfssl gencert -ca=ca-k8s-apiserver.pem -ca-key=ca-k8s-apiserver-key.pem -config=ca-k8s-apiserver-config.json -profile=kubernetes cert-k8s-controller-manager-sa-csr.json | cfssljson -bare cert-k8s-controller-manager-sa" + args: + chdir: "{{k8s_ca_conf_directory}}" + creates: "{{k8s_ca_conf_directory}}/cert-k8s-controller-manager-sa-key.pem" + tags: + - kubernetes-ca + +- name: Generate TLS certificate for kube-scheduler + shell: "cfssl gencert -ca=ca-k8s-apiserver.pem -ca-key=ca-k8s-apiserver-key.pem -config=ca-k8s-apiserver-config.json -profile=kubernetes cert-k8s-scheduler-csr.json | cfssljson -bare cert-k8s-scheduler" + args: + chdir: "{{k8s_ca_conf_directory}}" + creates: "{{k8s_ca_conf_directory}}/cert-k8s-scheduler-key.pem" + tags: + - kubernetes-ca diff --git a/roles/kubernetes-ca/templates/ca-etcd-config.json.j2 b/roles/kubernetes-ca/templates/ca-etcd-config.json.j2 new file mode 100644 index 0000000..b5f4a39 --- /dev/null +++ b/roles/kubernetes-ca/templates/ca-etcd-config.json.j2 @@ -0,0 +1,18 @@ +{ + "signing": { + "default": { + "expiry": "{{ ca_etcd_expiry }}" + }, + "profiles": { + "etcd": { + "usages": [ + "signing", + "key encipherment", + "server auth", + "client auth" + ], + "expiry": "{{ ca_etcd_expiry }}" + } + } + } +} diff --git a/roles/kubernetes-ca/templates/ca-etcd-csr.json.j2 b/roles/kubernetes-ca/templates/ca-etcd-csr.json.j2 new file mode 100644 index 0000000..817e631 --- /dev/null +++ b/roles/kubernetes-ca/templates/ca-etcd-csr.json.j2 @@ -0,0 +1,16 @@ +{ + "CN": "{{ca_etcd_csr_cn}}", + "key": { + "algo": "{{ca_etcd_csr_key_algo}}", + "size": {{ca_etcd_csr_key_size}} + }, + "names": [ + { + "C": "{{ca_etcd_csr_names_c}}", + "L": "{{ca_etcd_csr_names_l}}", + "O": "{{ca_etcd_csr_names_o}}", + "OU": "{{ca_etcd_csr_names_ou}}", + "ST": "{{ca_etcd_csr_names_st}}" + } + ] +} diff --git a/roles/kubernetes-ca/templates/ca-k8s-apiserver-config.json.j2 b/roles/kubernetes-ca/templates/ca-k8s-apiserver-config.json.j2 new file mode 100644 index 0000000..306db5f --- /dev/null +++ b/roles/kubernetes-ca/templates/ca-k8s-apiserver-config.json.j2 @@ -0,0 +1,18 @@ +{ + "signing": { + "default": { + "expiry": "{{ ca_k8s_apiserver_expiry }}" + }, + "profiles": { + "kubernetes": { + "usages": [ + "signing", + "key encipherment", + "server auth", + "client auth" + ], + "expiry": "{{ ca_k8s_apiserver_expiry }}" + } + } + } +} diff --git a/roles/kubernetes-ca/templates/ca-k8s-apiserver-csr.json.j2 b/roles/kubernetes-ca/templates/ca-k8s-apiserver-csr.json.j2 new file mode 100644 index 0000000..608b2b5 --- /dev/null +++ b/roles/kubernetes-ca/templates/ca-k8s-apiserver-csr.json.j2 @@ -0,0 +1,16 @@ +{ + "CN": "{{ca_k8s_apiserver_csr_cn}}", + "key": { + "algo": "{{ca_k8s_apiserver_csr_key_algo}}", + "size": {{ca_k8s_apiserver_csr_key_size}} + }, + "names": [ + { + "C": "{{ca_k8s_apiserver_csr_names_c}}", + "L": "{{ca_k8s_apiserver_csr_names_l}}", + "O": "{{ca_k8s_apiserver_csr_names_o}}", + "OU": "{{ca_k8s_apiserver_csr_names_ou}}", + "ST": "{{ca_k8s_apiserver_csr_names_st}}" + } + ] +} diff --git a/roles/kubernetes-ca/templates/cert-admin-csr.json.j2 b/roles/kubernetes-ca/templates/cert-admin-csr.json.j2 new file mode 100644 index 0000000..d3de6f7 --- /dev/null +++ b/roles/kubernetes-ca/templates/cert-admin-csr.json.j2 @@ -0,0 +1,16 @@ +{ + "CN": "{{k8s_admin_csr_cn}}", + "key": { + "algo": "{{k8s_admin_csr_key_algo}}", + "size": {{k8s_admin_csr_key_size}} + }, + "names": [ + { + "C": "{{k8s_admin_csr_names_c}}", + "L": "{{k8s_admin_csr_names_l}}", + "O": "{{k8s_admin_csr_names_o}}", + "OU": "{{k8s_admin_csr_names_ou}}", + "ST": "{{k8s_admin_csr_names_st}}" + } + ] +} diff --git a/roles/kubernetes-ca/templates/cert-etcd-csr.json.j2 b/roles/kubernetes-ca/templates/cert-etcd-csr.json.j2 new file mode 100644 index 0000000..fde0ec8 --- /dev/null +++ b/roles/kubernetes-ca/templates/cert-etcd-csr.json.j2 @@ -0,0 +1,16 @@ +{ + "CN": "{{etcd_csr_cn}}", + "key": { + "algo": "{{etcd_csr_key_algo}}", + "size": {{etcd_csr_key_size}} + }, + "names": [ + { + "C": "{{etcd_csr_names_c}}", + "L": "{{etcd_csr_names_l}}", + "O": "{{etcd_csr_names_o}}", + "OU": "{{etcd_csr_names_ou}}", + "ST": "{{etcd_csr_names_st}}" + } + ] +} diff --git a/roles/kubernetes-ca/templates/cert-k8s-apiserver-csr.json.j2 b/roles/kubernetes-ca/templates/cert-k8s-apiserver-csr.json.j2 new file mode 100644 index 0000000..7f8c557 --- /dev/null +++ b/roles/kubernetes-ca/templates/cert-k8s-apiserver-csr.json.j2 @@ -0,0 +1,16 @@ +{ + "CN": "{{k8s_apiserver_csr_cn}}", + "key": { + "algo": "{{k8s_apiserver_csr_key_algo}}", + "size": {{k8s_apiserver_csr_key_size}} + }, + "names": [ + { + "C": "{{k8s_apiserver_csr_names_c}}", + "L": "{{k8s_apiserver_csr_names_l}}", + "O": "{{k8s_apiserver_csr_names_o}}", + "OU": "{{k8s_apiserver_csr_names_ou}}", + "ST": "{{k8s_apiserver_csr_names_st}}" + } + ] +} diff --git a/roles/kubernetes-ca/templates/cert-k8s-controller-manager-csr.json.j2 b/roles/kubernetes-ca/templates/cert-k8s-controller-manager-csr.json.j2 new file mode 100644 index 0000000..99411a7 --- /dev/null +++ b/roles/kubernetes-ca/templates/cert-k8s-controller-manager-csr.json.j2 @@ -0,0 +1,16 @@ +{ + "CN": "{{k8s_controller_manager_csr_cn}}", + "key": { + "algo": "{{k8s_controller_manager_csr_key_algo}}", + "size": {{k8s_controller_manager_csr_key_size}} + }, + "names": [ + { + "C": "{{k8s_controller_manager_csr_names_c}}", + "L": "{{k8s_controller_manager_csr_names_l}}", + "O": "{{k8s_controller_manager_csr_names_o}}", + "OU": "{{k8s_controller_manager_csr_names_ou}}", + "ST": "{{k8s_controller_manager_csr_names_st}}" + } + ] +} diff --git a/roles/kubernetes-ca/templates/cert-k8s-controller-manager-sa-csr.json.j2 b/roles/kubernetes-ca/templates/cert-k8s-controller-manager-sa-csr.json.j2 new file mode 100644 index 0000000..8155a12 --- /dev/null +++ b/roles/kubernetes-ca/templates/cert-k8s-controller-manager-sa-csr.json.j2 @@ -0,0 +1,16 @@ +{ + "CN": "{{k8s_controller_manager_sa_csr_cn}}", + "key": { + "algo": "{{k8s_controller_manager_sa_csr_key_algo}}", + "size": {{k8s_controller_manager_sa_csr_key_size}} + }, + "names": [ + { + "C": "{{k8s_controller_manager_sa_csr_names_c}}", + "L": "{{k8s_controller_manager_sa_csr_names_l}}", + "O": "{{k8s_controller_manager_sa_csr_names_o}}", + "OU": "{{k8s_controller_manager_sa_csr_names_ou}}", + "ST": "{{k8s_controller_manager_sa_csr_names_st}}" + } + ] +} diff --git a/roles/kubernetes-ca/templates/cert-k8s-proxy-csr.json.j2 b/roles/kubernetes-ca/templates/cert-k8s-proxy-csr.json.j2 new file mode 100644 index 0000000..49f67be --- /dev/null +++ b/roles/kubernetes-ca/templates/cert-k8s-proxy-csr.json.j2 @@ -0,0 +1,16 @@ +{ + "CN": "{{k8s_kube_proxy_csr_cn}}", + "key": { + "algo": "{{k8s_kube_proxy_csr_key_algo}}", + "size": {{k8s_kube_proxy_csr_key_size}} + }, + "names": [ + { + "C": "{{k8s_kube_proxy_csr_names_c}}", + "L": "{{k8s_kube_proxy_csr_names_l}}", + "O": "{{k8s_kube_proxy_csr_names_o}}", + "OU": "{{k8s_kube_proxy_csr_names_ou}}", + "ST": "{{k8s_kube_proxy_csr_names_st}}" + } + ] +} diff --git a/roles/kubernetes-ca/templates/cert-k8s-scheduler-csr.json.j2 b/roles/kubernetes-ca/templates/cert-k8s-scheduler-csr.json.j2 new file mode 100644 index 0000000..52638d2 --- /dev/null +++ b/roles/kubernetes-ca/templates/cert-k8s-scheduler-csr.json.j2 @@ -0,0 +1,16 @@ +{ + "CN": "{{k8s_scheduler_csr_cn}}", + "key": { + "algo": "{{k8s_scheduler_csr_key_algo}}", + "size": {{k8s_scheduler_csr_key_size}} + }, + "names": [ + { + "C": "{{k8s_scheduler_csr_names_c}}", + "L": "{{k8s_scheduler_csr_names_l}}", + "O": "{{k8s_scheduler_csr_names_o}}", + "OU": "{{k8s_scheduler_csr_names_ou}}", + "ST": "{{k8s_scheduler_csr_names_st}}" + } + ] +} diff --git a/roles/kubernetes-ca/templates/cert-worker-csr.json.j2 b/roles/kubernetes-ca/templates/cert-worker-csr.json.j2 new file mode 100644 index 0000000..6fbd88e --- /dev/null +++ b/roles/kubernetes-ca/templates/cert-worker-csr.json.j2 @@ -0,0 +1,16 @@ +{ + "CN": "system:node:{{hostvars[workerHost]['ansible_hostname']}}", + "key": { + "algo": "{{k8s_worker_csr_key_algo}}", + "size": {{k8s_worker_csr_key_size}} + }, + "names": [ + { + "C": "{{k8s_worker_csr_names_c}}", + "L": "{{k8s_worker_csr_names_l}}", + "O": "{{k8s_worker_csr_names_o}}", + "OU": "{{k8s_worker_csr_names_ou}}", + "ST": "{{k8s_worker_csr_names_st}}" + } + ] +} diff --git a/roles/kubernetes-ca/tests/inventory b/roles/kubernetes-ca/tests/inventory new file mode 100644 index 0000000..d18580b --- /dev/null +++ b/roles/kubernetes-ca/tests/inventory @@ -0,0 +1 @@ +localhost \ No newline at end of file diff --git a/roles/kubernetes-ca/tests/test.yml b/roles/kubernetes-ca/tests/test.yml new file mode 100644 index 0000000..a31e13a --- /dev/null +++ b/roles/kubernetes-ca/tests/test.yml @@ -0,0 +1,5 @@ +--- +- hosts: localhost + remote_user: root + roles: + - . \ No newline at end of file diff --git a/roles/kubernetes-ca/vars/main.yml b/roles/kubernetes-ca/vars/main.yml new file mode 100644 index 0000000..ed97d53 --- /dev/null +++ b/roles/kubernetes-ca/vars/main.yml @@ -0,0 +1 @@ +---