Démarrer avec Terraform Cloud
Terraform Cloud, lancé en 2018 par HashiCorp, fournit gratuitement aux développeurs un espace de stockage cloud pour gérer les states Terraform. Cette version s’adresse avant tout aux petites comprenant jusqu’à cinq développeurs.
Pour les plus grosses structures plusieurs offres ↗ sont disponibles donnant accès à plus de fonctionnalités. Il existe également une distribution auto-hébergée de Terraform Cloud. Il offre aux entreprises une instance privée qui inclut les fonctionnalités avancées disponibles dans Terraform Cloud.
Dans ce billet, je ne vais aborder que l’utilisation de la version gratuite de Terraform Cloud.
Création du compte Terraform Cloud
Il suffit de se rendre sur la page suivante ↗ et de s’inscrire.
Association de votre compte Terraform Cloud
Bien sûr, il faut que la CLI de Terraform soit installée, si ce n’est pas le cas rendez-vous sur la page suivante ↗ et de suivre les instructions.
Une fois installé il suffit de taper la commande terraform login
pour vous
connecter à votre compte Terraform Cloud. Elle va vous proposer de vous
rendre sur la page de génération des Tokens.
Il suffit de saisir un nom et de copier le token dans la cli :
terraform login
Open the following URL to access the tokens page for app.terraform.io: https://app.terraform.io/app/settings/tokens?source=terraform-login
Generate a token using your browser, and copy-paste it into this prompt.
Terraform will store the token in plain text in the following filefor use by subsequent commands: /home/vagrant/.terraform.d/credentials.tfrc.json
Token for app.terraform.io: Enter a value: xxxxxxxxxxxxxxxxxxx
Welcome to Terraform Cloud! - ---------- ------- --- ----- --- Documentation: terraform.io/docs/cloud -------- -
La CLI stocke le token dans un fichier credentials.tfrc.json
du répertoire
${HOME}/.terraform.d
. Donc pas de souci au niveau de son enregistrement dans
un repository git.
Enregistrement du state dans Terraform Cloud
Il suffit d’indiquer le backend remote dans votre configuration en remplaçant le nom de votre organisation indiquée dans Terraform Cloud:
terraform { backend "remote" { hostname = "app.terraform.io" organization = "<YOUR-ORG-NAME>"
workspaces { name = "test" } }}
Ici, nous indiquons clairement le nom du workspace. Si vous voulez utiliser plusieurs workspace, il faut plutôt utiliser la clé préfixe au lieu de nom :
terraform { backend "remote" { hostname = "app.terraform.io" organization = "<YOUR-ORG-NAME>"
workspaces { prefix = "test-" } }}
terraform workspace new dev 6s Py ansible Ruby 2.7.2 tf prod vagrant@devbox 11:08:18Created and switched to workspace "dev"!
You're now on a new, empty workspace. Workspaces isolate their state,so if you run "terraform plan" Terraform will not see any existing statefor this configuration.
terraform plan 3s Py ansible Ruby 2.7.2 tf dev vagrant@devbox 11:39:20Running plan in the remote backend. Output will stream here. Pressing Ctrl-Cwill stop streaming the logs, but will not stop the plan running remotely.
Preparing the remote plan...
To view this run in a browser, visit:https://app.terraform.io/app/s.robert/test-dev/runs/run-c6fLDMJAJVvUcW2i
Waiting for the plan to start...
Utilisation de secrets dans Terraform Cloud
Si nous reprenons l’exemple du déploiement de notre infrastructure sur AWS, nous devons adapter nos fichiers de configuration. En effet, nos données sensibles, ne sont pas disponibles dans Terraform Cloud comme nos ID AWS ou notre clé SSH.
Il faut donc les ajouter au fichier variables.tf
:
variable "SSH_KEY" { type = string sensitive = true}
variable "AWS_ACCESS_KEY_ID" { type = string sensitive = true}
variable "AWS_SECRET_ACCESS_KEY" { type = string sensitive = true}
Comme je ne veux pas qu’elle apparaisse dans les sorties je les mets de suite en
mode sensitive
.
Ensuite dans notre fichier main.tf
je dois aussi les intégrer :
terraform { required_providers { aws = { source = "hashicorp/aws" version = "~> 3.64" } } backend "remote" { hostname = "app.terraform.io" organization = "s.robert" workspaces { prefix = "test-" } }}
provider "aws" { region = var.aws_zone access_key = var.AWS_ACCESS_KEY_ID secret_key = var.AWS_SECRET_ACCESS_KEY}
data "aws_ami" "latest-rocky" { most_recent = true owners = ["679593333241"]
filter { name = "root-device-type" values = ["ebs"] }
filter { name = "virtualization-type" values = ["hvm"] } filter { name = "name" values = ["Rocky Linux 8.4-*"] }}
resource "aws_key_pair" "ssh-key" { key_name = "ssh-key" public_key = var.SSH_KEY}
resource "aws_instance" "gitlab-runner" { ami = data.aws_ami.latest-rocky.id instance_type = var.gitlab_runner_instance_type key_name = "ssh-key" associate_public_ip_address = true connection { type = "ssh" host = "${self.private_ip}" } tags = { Name = "gitlab-runner" }}
resource "aws_default_vpc" "default" { tags = { Name = "Default VPC" }}
resource "aws_default_security_group" "default" { vpc_id = "${aws_default_vpc.default.id}" ingress { # TLS (change to whatever ports you need) from_port = 22 to_port = 22 protocol = "tcp" # Please restrict your ingress to only necessary IPs and ports. # Opening to 0.0.0.0/0 can lead to security vulnerabilities. cidr_blocks = ["0.0.0.0/0"] } egress { from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] }}output "ip" { value = "${aws_instance.gitlab-runner.public_ip}"}
Vous remarquerez que j’ai ajouté access_key
et secret_key
à la déclaration
du provider.
Il nous faut maintenant créer dans notre compte Terraform Cloud ces
variables. Il faut se rendre dans le menu settings/Organisation
ou
settings/Variables Sets
.
En premier, donnez un nom et une description à votre variable et choisir à quel workspace il s’applique. On peut dire créer des variables propres à chaque environnement.
Ensuite créer vos variables avec la catégorie terraform et sensitive :
Ensuite n’oubliez pas de cliquer sur [Create Variable Set]
Si vos variables ne sont pas correctement créés vous obtiendrez ce message d’erreur lors du plan :
│ Error: No value for required variable││ on variables.tf line 23:│ 23: variable "AWS_ACCESS_KEY_ID" {││ The root module input variable "AWS_ACCESS_KEY_ID" is not set, and has no│ default value. Use a -var or -var-file command line argument to provide a│ value for this variable.
ou :
│ Error: error configuring Terraform AWS Provider: no valid credential sources for Terraform AWS Provider found.││ Please see https://registry.terraform.io/providers/hashicorp/aws│ for more information about providing credentials.││ Error: NoCredentialProviders: no valid providers in chain│ caused by: EnvAccessKeyNotFound: failed to find credentials in the environment.│ SharedCredsLoad: failed to load profile, .│ EC2RoleRequestError: no EC2 instance role found│ caused by: RequestError: send request failed
Application de notre configuration.
terraform apply
Running apply in the remote backend. Output will stream here. Pressing Ctrl-Cwill cancel the remote apply if it's still pending. If the apply started itwill stop streaming the logs, but will not stop the apply running remotely.
Preparing the remote apply...
To view this run in a browser, visit:https://app.terraform.io/app/s-robert/test-prod/runs/run-xxxxxxx
Waiting for the plan to start...
Terraform v1.0.11on linux_amd64Configuring remote state backend...Initializing Terraform configuration...
aws_default_vpc.default: Creating...aws_key_pair.ssh-key: Creating...aws_instance.gitlab-runner: Creating...aws_key_pair.ssh-key: Creation complete after 1s [id=ssh-key]aws_default_vpc.default: Still creating... [10s elapsed]aws_instance.gitlab-runner: Still creating... [10s elapsed]aws_default_vpc.default: Creation complete after 15s [id=vpc-0a77acc75bf90db8d]aws_default_security_group.default: Creating...aws_default_security_group.default: Creation complete after 4s [id=sg-03471ff7b3b521490]aws_instance.gitlab-runner: Still creating... [20s elapsed]aws_instance.gitlab-runner: Still creating... [30s elapsed]aws_instance.gitlab-runner: Creation complete after 36s [id=i-03c114c2c7c4694df]
Apply complete! Resources: 4 added, 0 changed, 0 destroyed.
Outputs:
ip = "xx.xx.xxx.xxx"
Notre VM s’est correctement instancié. Vérifions que nos secrets le sont bien :
terraform show
# aws_key_pair.ssh-key:resource "aws_key_pair" "ssh-key" { arn = "arn:aws:ec2:eu-west-3:434124198450:key-pair/ssh-key" fingerprint = "4f:fc:60:22:7e:3d:80:64:e7:b1:01:0b:62:0d:04:d0" id = "ssh-key" key_name = "ssh-key" key_pair_id = "key-0c420cf4a5ddc5840" public_key = (sensitive) tags_all = {}}
Notre variable public_key
est bien masquée !