125 votes

Configuration initiale du backend terraform en utilisant terraform

Je commence tout juste à utiliser terraform et j'aimerais pouvoir utiliser AWS S3 comme backend pour stocker l'état de mes projets.

terraform {
    backend "s3" {
      bucket = "tfstate"
      key = "app-state"
      region = "us-east-1"
    }
}

Je pense qu'il est judicieux de configurer mon seau S3, les groupes IAM et les politiques pour l'infrastructure de stockage dorsale avec terraform également.

Si je configure l'état de mon backend avant d'appliquer l'infrastructure initiale de terraform, il se plaint raisonnablement que le bucket du backend n'est pas encore créé. Ma question est donc la suivante : comment puis-je configurer mon backend terraform avec terraform, tout en conservant l'état du backend suivi par terraform ? Cela ressemble à un problème de poupées gigognes.

J'ai quelques idées sur la façon de script autour de cela, par exemple, en vérifiant si le seau existe ou si un certain état a été défini, puis en démarrant terraform et enfin en copiant le tfstate terraform vers s3 à partir du système de fichiers local après la première exécution. Mais avant de m'engager dans cette voie laborieuse, je voulais m'assurer que je ne manquais pas quelque chose d'évident.

3 votes

C'est une bonne question. Pour information, nous avions un projet séparé de TF "bootstrap", qui reposait à son tour sur un bucket super-minimal approvisionné manuellement.

1 votes

Oui, j'ai fait quelque chose de similaire où un projet bootstrap copie à travers un tas d'aides scripts et de configurations de fournisseurs pour un projet et crée également un bucket S3 versionné et une table de verrouillage DynamoDb s'il n'existe pas en utilisant le CLI AWS. Ce serait bien si nous pouvions faire cela dans Terraform, mais lorsque j'ai essayé, c'était trop compliqué pour en valoir la peine.

2 votes

Terragrunt peut également s'en charger pour vous, ce qui est très pratique si vous souhaitez passer à un autre seau. github.com/gruntwork-io/terragrunt

135voto

Austin Davis Points 1431

Pour configurer cela en utilisant l'état distant de terraform, j'ai généralement un dossier séparé appelé remote-state dans mon dossier terraform de dev et prod.

Les éléments suivants main.tf va configurer votre état distant pour ce que vous avez posté :

provider "aws" {
  region = "us-east-1"
}

resource "aws_s3_bucket" "terraform_state" {
  bucket = "tfstate"

  versioning {
    enabled = true
  }

  lifecycle {
    prevent_destroy = true
  }
}

resource "aws_dynamodb_table" "terraform_state_lock" {
  name           = "app-state"
  read_capacity  = 1
  write_capacity = 1
  hash_key       = "LockID"

  attribute {
    name = "LockID"
    type = "S"
  }
}

Ensuite, entrez dans ce dossier en utilisant cd remote-state et exécutez terraform init && terraform apply - cela ne doit être exécuté qu'une seule fois. Vous pouvez ajouter quelque chose au nom du seau et de la table dynamodb pour séparer vos différents environnements.

10 votes

Réponse brillante. Pour info, si vous lisez "Terraform Up and Running" et que vous êtes bloqué au chapitre 3 "backends" (qui utilise une ancienne version de terreform), voici la solution.

1 votes

Je suppose que vous utilisez le terraform_state_lock comme un mutex pour écrire l'état, mais qu'est-ce qui lit/écrit à partir de celui-ci ? Est-ce que terraform fait quelque chose dans les coulisses ? Que se passe-t-il si vous excluez la ressource aws_dynamodb_table ?

2 votes

Ah -- J'ai compris. C'est parce que le backend s3 intégré supporte le verrouillage via une table dynamodb en utilisant le paramètre dynamodb_table : terraform.io/docs/backends/types/s3.html#dynamodb_table

26voto

Matt Lavin Points 145

Sur la base de l'excellente contribution d'Austin Davis, voici une variante que j'utilise et qui inclut une exigence de cryptage des données :

provider "aws" {
  region = "us-east-1"
}

resource "aws_s3_bucket" "terraform_state" {
  bucket = "tfstate"

  versioning {
    enabled = true
  }

  lifecycle {
    prevent_destroy = true
  }
}

resource "aws_dynamodb_table" "terraform_state_lock" {
  name           = "app-state"
  read_capacity  = 1
  write_capacity = 1
  hash_key       = "LockID"

  attribute {
    name = "LockID"
    type = "S"
  }
}

resource "aws_s3_bucket_policy" "terraform_state" {
  bucket = "${aws_s3_bucket.terraform_state.id}"
  policy =<<EOF
{
  "Version": "2012-10-17",
  "Id": "RequireEncryption",
   "Statement": [
    {
      "Sid": "RequireEncryptedTransport",
      "Effect": "Deny",
      "Action": ["s3:*"],
      "Resource": ["arn:aws:s3:::${aws_s3_bucket.terraform_state.bucket}/*"],
      "Condition": {
        "Bool": {
          "aws:SecureTransport": "false"
        }
      },
      "Principal": "*"
    },
    {
      "Sid": "RequireEncryptedStorage",
      "Effect": "Deny",
      "Action": ["s3:PutObject"],
      "Resource": ["arn:aws:s3:::${aws_s3_bucket.terraform_state.bucket}/*"],
      "Condition": {
        "StringNotEquals": {
          "s3:x-amz-server-side-encryption": "AES256"
        }
      },
      "Principal": "*"
    }
  ]
}
EOF
}

18voto

djt Points 3457

Comme vous l'avez découvert, vous ne pouvez pas utiliser terraform pour construire les composants dont terraform a besoin en premier lieu.

Bien que je comprenne l'envie de faire en sorte que la terraforme "suive tout", c'est très difficile, et c'est plus un casse-tête qu'il n'en vaut la peine.

Je gère généralement cette situation en créant un simple shell bootstrap script. Il crée des choses comme :

  1. Le seau s3 pour le stockage de l'état
  2. Ajoute le versioning au dit seau
  3. un utilisateur et un groupe IAM terraform avec certaines politiques dont j'aurai besoin pour les constructions terraform

Alors que vous ne devriez avoir besoin de l'exécuter qu'une seule fois (techniquement), je trouve que lorsque je développe un nouveau système, je fais tourner et je démonte les choses à plusieurs reprises. Donc avoir ces étapes dans un script rend cela beaucoup plus simple.

Je construis généralement le script pour être idempotent. De cette façon, vous pouvez l'exécuter plusieurs fois sans vous soucier de créer des doublons (buckets, utilisateurs, etc.).

8 votes

En fait, vous pouvez utiliser Terraform pour construire les composants d'état distants (seau S3 et table DynamoDB) - il suffit d'utiliser un sous-dossier distinct pour la construction de ceux-ci, qui possède son propre fichier d'état Terraform (local). Voir cette réponse .

15voto

samstav Points 469

J'ai créé un module de terraformation avec quelques commandes/instructions de démarrage pour résoudre ce problème :

https://github.com/samstav/terraform-aws-backend

Il y a des instructions détaillées dans le README, mais l'essentiel est là :

# conf.tf

module "backend" {
  source         = "github.com/samstav/terraform-aws-backend"
  backend_bucket = "terraform-state-bucket"
}

Ensuite, dans votre shell (assurez-vous que vous n'avez pas écrit votre terraform {} encore) :

terraform get -update
terraform init -backend=false
terraform plan -out=backend.plan -target=module.backend
terraform apply backend.plan

Maintenant, écrivez votre terraform {} bloc :

# conf.tf

terraform {
  backend "s3" {
    bucket         = "terraform-state-bucket"
    key            = "states/terraform.tfstate"
    dynamodb_table = "terraform-lock"
  }
}

Et ensuite vous pouvez réinitialiser :

terraform init -reconfigure

8voto

Lev Points 60

Ce que je fais habituellement, c'est de commencer sans backend distant pour créer l'infrastructure initiale comme vous l'avez dit, S3, rôles IAM et autres choses essentielles. Une fois que c'est fait, j'ajoute la configuration du backend et j'exécute terraform init pour migrer vers S3.

Ce n'est pas la meilleure solution, mais dans la plupart des cas, je ne reconstruis pas tout mon environnement tous les jours, donc cette approche semi-automatique est suffisante. Je sépare également les "couches" suivantes (VPC, sous-réseaux, IGW, NAT, etc.) de l'infrastructure en différents états.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X