Terraform example for deploying Kubernetes and Rancher on existing infrastructure
resource "rke_cluster" "rancher" {
ssh_agent_auth = true
ignore_docker_version = true
kubernetes_version = var.kubernetes_version
dynamic "nodes" {
for_each = var.rancher_nodes
content {
address = nodes.key
hostname_override = nodes.value
user = var.ssh_user
role = ["controlplane", "etcd", "worker"]
}
}
}
resource "kubernetes_namespace" "cattle-system" {
metadata {
name = "cattle-system"
}
}
resource "kubernetes_secret" "tls_ca" {
metadata {
name = "tls-ca"
namespace = "cattle-system"
}
data = {
"cacerts.pem" = file("${path.module}/resources/cacerts.pem")
}
depends_on = [
rke_cluster.rancher
]
}
resource "kubernetes_secret" "tls_rancher_ingress" {
metadata {
name = "tls-rancher-ingress"
namespace = "cattle-system"
}
type = "kubernetes.io/tls"
data = {
"tls.crt" = file("${path.module}/resources/tls.crt")
"tls.key" = file("${path.module}/resources/tls.key")
}
depends_on = [
rke_cluster.rancher
]
}
resource "helm_release" "rancher" {
name = "rancher"
chart = "rancher"
version = var.rancher_version
namespace = "cattle-system"
create_namespace = true
repository = "https://releases.rancher.com/server-charts/latest"
timeout = 600
set {
name = "hostname"
value = var.rancher_hostname
}
set {
name = "antiAffinity"
value = "required"
}
set {
name = "ingress.tls.source"
value = "secret"
}
set {
name = "privateCA"
value = "true"
}
depends_on = [
kubernetes_secret.tls_ca,
kubernetes_secret.tls_rancher_ingress
]
}
resource "null_resource" "wait_for_rancher" {
provisioner "local-exec" {
command = <<EOF
while [ "$${resp}" != pong ]; do
resp=$(curl -sSk -m 2 --insecure "https://$${RANCHER_HOSTNAME}/ping")
echo "Rancher response: $${resp}"
if [ "$${resp}" != "pong" ]; then
sleep 10
fi
done
EOF
environment = {
RANCHER_HOSTNAME = var.rancher_hostname
}
}
depends_on = [
helm_release.rancher
]
}
resource "rancher2_bootstrap" "admin" {
provider = rancher2.bootstrap
password = var.admin_password
telemetry = true
depends_on = [
null_resource.wait_for_rancher
]
}
resource "rancher2_token" "rancher-token" {
provider = rancher2
}
resource "local_file" "kube_cluster_yaml" {
filename = "${path.root}/kube_config_cluster.yml"
content = rke_cluster.rancher.kube_config_yaml
depends_on = [rke_cluster.rancher]
}
output "rancher_url" {
value = var.rancher_hostname
}
data "rancher2_user" "admin" {
username = "admin"
depends_on = [rancher2_bootstrap.admin]
}
resource "rancher2_auth_config_activedirectory" "activedirectory" {
servers = var.ad_server
tls = false
port = 389
service_account_username = var.ad_username
service_account_password = var.ad_password
test_username = var.ad_username
test_password = var.ad_password
default_login_domain = var.ad_default_login_domain
user_search_base = var.ad_user_search_base
group_search_base = var.ad_group_search_base
nested_group_membership_enabled = true
access_mode = "unrestricted"
allowed_principal_ids = ["local://${data.rancher2_user.admin.id}", "activedirectory_group://CN=SRE,OU=Groups,DC=tetromino,DC=local"]
count = var.enable_active_directory ? 1 : 0
}
resource "rancher2_global_role_binding" "sre" {
name = "sre"
global_role_id = "admin"
group_principal_id = "activedirectory_group://cn=sre,${var.ad_group_search_base}"
}
resource "rancher2_global_role_binding" "dev" {
name = "dev"
global_role_id = "user"
group_principal_id = "activedirectory_group://cn=Dev,${var.ad_group_search_base}"
}
provider "kubernetes" {
config_context = "local"
config_path = local_file.kube_cluster_yaml.filename
}
provider "helm" {
kubernetes {
config_path = local_file.kube_cluster_yaml.filename
}
}
provider "rancher2" {
alias = "bootstrap"
api_url = "https://${var.rancher_hostname}"
bootstrap = true
insecure = true
}
provider "rancher2" {
api_url = rancher2_bootstrap.admin.url
token_key = rancher2_bootstrap.admin.token
insecure = true
}
variable "kubernetes_version" {
description = "Version of Kubernetes to deploy"
default = "v1.19.3-rancher1-2"
}
variable "rancher_version" {
description = "Version of Rancher Server to deploy"
default = "2.5.5"
}
variable "rancher_hostname" {
description = "Rancher FQDN"
default = "rancher.192.168.1.210.dnsify.me"
}
variable "ssh_user" {
description = "Username for SSH access to VMs"
default = "nick"
}
variable "admin_password" {
description = "Rancher admin password"
default = "admin"
}
variable "downstream_kubernetes_version" {
description = "Version of Kubernetes to deploy on downstream cluster"
default = "v1.19.4-rancher1-1"
}
variable "rancher_nodes" {
type = map(string)
default = {
"192.168.1.86" = "rancher0"
"192.168.1.9" = "rancher1"
"192.168.1.7" = "rancher2"
}
}
variable "downstream_cluster_nodes" {
type = map(string)
default = {
"192.168.1.50" = "--controlplane --etcd"
"192.168.1.51" = "--worker"
}
}
variable "enable_active_directory" {
description = "Whether or not to enable Rancher AD integration"
default = false
}
variable "ad_server" {
description = "Active Directory server(s) IP or hostname"
default = [""]
}
variable "ad_username" {
description = "Active Directory service account used for lookups"
default = ""
}
variable "ad_password" {
description = "Active Directory password"
default = ""
}
variable "ad_user_search_base" {
description = "AD user search base"
default = ""
}
variable "ad_group_search_base" {
description = "AD group search base"
default = ""
}
variable "ad_default_login_domain" {
description = "Default AD login domain"
default = ""
}
rancher_hostname = "rancher.192.168.1.210.dnsify.me"
enable_active_directory = true
ad_username = "TETROMINO\\SArancher"
ad_password = "2a09a433-fa38-4d3f-9009-2527baf27434"
ad_server = ["192.168.1.220"]
ad_user_search_base = "dc=tetromino,dc=local"
ad_group_search_base = "OU=Groups,DC=tetromino,DC=local"
ad_default_login_domain = "TETROMINO"
rancher_nodes = {
"192.168.1.42" = "rancher0"
"192.168.1.14" = "rancher1"
"192.168.1.30" = "rancher2"
}
kubernetes_version = "v1.19.6-rancher1-1"
terraform {
required_providers {
helm = {
source = "hashicorp/helm"
}
kubernetes = {
source = "hashicorp/kubernetes"
}
local = {
source = "hashicorp/local"
}
null = {
source = "hashicorp/null"
}
rancher2 = {
source = "rancher/rancher2"
}
rke = {
source = "rancher/rke"
version = ">= 1.1.7"
}
}
required_version = ">= 0.13"
}