Dominik Miklaszewski
by Dominik Miklaszewski

Categories

Tags

Siedzę sobie nad projektem w AWSie, terraformując zawzięcie. Niczego wrażliwego nie publikuję na GitHubie, aczkolwiek pałętają mi się po dysku pliki stanu terraforma (terraform.tfstate). Gdybym miał w domu korporację, w której dbano by o security, cybersecurity, compliance, ochronę danych osobowych, danych wrażliwych, tajemnicę bankową, i wszelkie inne bardzo tajne i super-wrażliwe tajemnice, to musiałbym pewnie użyć (i zapłacić!) Terraform Cloud-a jako “provider-a” dla terraforma. Albo co najmniej szyfrowanego S3 z włączonym wersjonowaniem i własnym kluczem szyfrującym.

Terraform i Vault

W Vaulcie trzymam kredki dla AWSa (iam_user). Backup (snapshot) magazynu danych Vaulta leci na szyfrowany dysk. Załatwia to Consul, który serwuje Vaultowi rozproszony storage - RAFTem po HTTPSie (co prawda to rozproszenie jest trochę symulowane - bo jak szlag trafi NUC-a to i moją wirtualną sieć i VMki). Ale zostanie mi dysk :)

Sprawa jest prosta - w Vaulcie wrzucam kredki do kv/aws i kv/terraform (o czym za chwilę). A potem każę terraformowi, je sobie pobrać wykorzystując terraformowe źródło danych vault_generic_secret a potem kojarząc z dostawcą.

providers.tf:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 
data "vault_generic_secret" "tf_token" {
  path = "kv/terraform"
}

data "vault_generic_secret" "aws_creds" {
  path = "kv/aws"
}

provider "aws" {
  region  = data.vault_generic_secret.aws_creds.data["DEFAULT_REGION"]
  access_key = data.vault_generic_secret.aws_creds.data["AWS_ACCESS_KEY_ID"]
  secret_key = data.vault_generic_secret.aws_creds.data["AWS_SECRET_ACCESS_KEY"]
}

provider "consul" {
  token = data.vault_generic_secret.tf_token.data["access_token"]
} 
 

Terraform i Consul

Pliki stanu terraforma pakuję do Consula. Tenże robi za backend dla terraforma. A konkretnie to za backendowy key-value store. Ale taki pojemniejszy niż Vault. Za to bez szyfrowania at-rest. Co prawda padła propozycja, by Vault stał się takim właściwym backendem, póki co jednak Hashicorp nie rozważa takiej ścieżki rozwoju.

Tutaj też, konfiguracja jest dość prosta i szybka. Po skonfigurowaniu backend.tf i wykonaniu komendy terraform init, terraform zapyta o migrację i zamelduje wykonanie zadania. Poniżej kawałek “meldunku”:

$ terraform init

Initializing the backend...
Do you want to copy existing state to the new backend?
  Pre-existing state was found while migrating the previous "local" backend to the
  newly configured "consul" backend. No existing state was found in the newly
  configured "consul" backend. Do you want to copy this state to the new "consul"
  backend? Enter "yes" to copy and "no" to start with an empty state.

  Enter a value: yes


Successfully configured the backend "consul"! Terraform will automatically
use this backend unless the backend configuration changes.

Initializing provider plugins...
- Reusing previous version of hashicorp/vault from the dependency lock file
[..]

a brakującym kawałkiem układanki jest ten oto backend.tf:

1
2
3
4
5
6
7
8
9
10
11
 
terraform {
  backend "consul" {
    address      = "powernukeint.nukelab.home:8501"
    scheme       = "https"
    path         = "terraform/aws/project1/terraform.tfstate"
    lock         = true
    gzip         = false
  }
}
 

Brakuje tu jednej linijki z tokenem. Ta jest jednak niepotrzebna, bo temat załatwia zdefiniowane źródło danych w Vaulcie. No i sobie to tak działa. Tym sposobem unikamy nawet przypadkowej publikacji plików stanu w repozytorium i namnażania tych plików w lokalnym systemie plików. Consul i Vault mają kontrolę dostępu. No i jeden i drugi jest dostępny przez odpowiedni token. Vault - źródło danych uwierzytelniających, Consul - w miarę bezpieczna przechowalnia plików stanu.

TFState w Consulu