Loading search data...

Terraform Cloud et le backend remote

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 sur 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.

Terraform cloud login

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 file
for 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:18
Created 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 state
for this configuration.

terraform plan                                                                                   3s Py ansible Ruby 2.7.2 tf dev vagrant@devbox 11:39:20
Running plan in the remote backend. Output will stream here. Pressing Ctrl-C
will 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...

Terraform cloud workspace

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 quelle 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 settings/Variables Sets.

Terraform cloud variable set

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 :

Terraform cloud variable set

Ensuite n’oubliez pas de cliquer sur [Create Variable Set]

Si vous variables ne sont pas correctement créé 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-C
will cancel the remote apply if it's still pending. If the apply started it
will 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.11
on linux_amd64
Configuring 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!

Mots clés :

devops tutorials infra as code terraform

Si vous avez apprécié cet article de blog, vous pouvez m'encourager à produire plus de contenu en m'offrant un café sur Ko-Fi. Vous pouvez aussi passer votre prochaine commande sur amazon, sans que cela ne nous coûte plus cher, via ce lien. Je vous remercie de votre soutien