{"id":9738,"date":"2023-04-12T15:30:11","date_gmt":"2023-04-12T14:30:11","guid":{"rendered":"https:\/\/blog.capdata.fr\/?p=9738"},"modified":"2023-04-12T15:30:11","modified_gmt":"2023-04-12T14:30:11","slug":"workspaces-terraform-avec-aws-s3-et-dynamodb","status":"publish","type":"post","link":"https:\/\/blog.capdata.fr\/index.php\/workspaces-terraform-avec-aws-s3-et-dynamodb\/","title":{"rendered":"Workspaces Terraform avec AWS S3 et DynamoDB"},"content":{"rendered":"<a class=\"synved-social-button synved-social-button-share synved-social-size-24 synved-social-resolution-single synved-social-provider-twitter nolightbox\" data-provider=\"twitter\" target=\"_blank\" rel=\"nofollow\" title=\"Share on Twitter\" href=\"https:\/\/twitter.com\/intent\/tweet?url=https%3A%2F%2Fblog.capdata.fr%2Findex.php%2Fwp-json%2Fwp%2Fv2%2Fposts%2F9738&#038;text=Article%20sur%20le%20blog%20de%20la%20Capdata%20Tech%20Team%20%3A%20\" style=\"font-size: 0px;width:24px;height:24px;margin:0;margin-bottom:5px;margin-right:5px\"><img loading=\"lazy\" decoding=\"async\" alt=\"twitter\" title=\"Share on Twitter\" class=\"synved-share-image synved-social-image synved-social-image-share\" width=\"24\" height=\"24\" style=\"display: inline;width:24px;height:24px;margin: 0;padding: 0;border: none;box-shadow: none\" src=\"https:\/\/blog.capdata.fr\/wp-content\/plugins\/social-media-feather\/synved-social\/image\/social\/regular\/48x48\/twitter.png\" \/><\/a><a class=\"synved-social-button synved-social-button-share synved-social-size-24 synved-social-resolution-single synved-social-provider-linkedin nolightbox\" data-provider=\"linkedin\" target=\"_blank\" rel=\"nofollow\" title=\"Share on Linkedin\" href=\"https:\/\/www.linkedin.com\/shareArticle?mini=true&#038;url=https%3A%2F%2Fblog.capdata.fr%2Findex.php%2Fwp-json%2Fwp%2Fv2%2Fposts%2F9738&#038;title=Workspaces%20Terraform%20avec%20AWS%20S3%20et%20DynamoDB\" style=\"font-size: 0px;width:24px;height:24px;margin:0;margin-bottom:5px;margin-right:5px\"><img loading=\"lazy\" decoding=\"async\" alt=\"linkedin\" title=\"Share on Linkedin\" class=\"synved-share-image synved-social-image synved-social-image-share\" width=\"24\" height=\"24\" style=\"display: inline;width:24px;height:24px;margin: 0;padding: 0;border: none;box-shadow: none\" src=\"https:\/\/blog.capdata.fr\/wp-content\/plugins\/social-media-feather\/synved-social\/image\/social\/regular\/48x48\/linkedin.png\" \/><\/a><a class=\"synved-social-button synved-social-button-share synved-social-size-24 synved-social-resolution-single synved-social-provider-mail nolightbox\" data-provider=\"mail\" rel=\"nofollow\" title=\"Share by email\" href=\"mailto:?subject=Workspaces%20Terraform%20avec%20AWS%20S3%20et%20DynamoDB&#038;body=Article%20sur%20le%20blog%20de%20la%20Capdata%20Tech%20Team%20%3A%20:%20https%3A%2F%2Fblog.capdata.fr%2Findex.php%2Fwp-json%2Fwp%2Fv2%2Fposts%2F9738\" style=\"font-size: 0px;width:24px;height:24px;margin:0;margin-bottom:5px\"><img loading=\"lazy\" decoding=\"async\" alt=\"mail\" title=\"Share by email\" class=\"synved-share-image synved-social-image synved-social-image-share\" width=\"24\" height=\"24\" style=\"display: inline;width:24px;height:24px;margin: 0;padding: 0;border: none;box-shadow: none\" src=\"https:\/\/blog.capdata.fr\/wp-content\/plugins\/social-media-feather\/synved-social\/image\/social\/regular\/48x48\/mail.png\" \/><\/a><h2><span style=\"text-decoration: underline;\"><span style=\"color: #ff0000; text-decoration: underline;\"><em><strong>I] Introduction:<\/strong><\/em><\/span><\/span><\/h2>\n<p>Terraform est une application dite &#8220;stateful&#8221;. C&#8217;est-\u00e0-dire que toutes les modifications apport\u00e9es \u00e0 votre infrastructure via cet outil sont stock\u00e9es dans un fichier State (\u00e9tat) au format json nomm\u00e9 <em>terraform.tfstate<\/em>. Ce fichier est cr\u00e9\u00e9 lors de la premi\u00e8re ex\u00e9cution de votre code terraform et par d\u00e9faut positionn\u00e9 localement au m\u00eame endroit que votre code terraform.<\/p>\n<p>A chaque ex\u00e9cution suivante via un <em>terraform apply<\/em> par exemple, le fichier<em> terraform.tfstate<\/em> repr\u00e9sentant alors l&#8217;\u00e9tat dans lequel doit se trouver votre infrastructure est compar\u00e9 \u00e0 votre code terraform afin d&#8217;en d\u00e9duire les ajouts (to <em>add<\/em>), changements (<em>to change<\/em>), suppression (<em>to destroy<\/em>) \u00e0 apporter et donc d&#8217;\u00e9tablir son plan. Terraform positionnera une sauvegarde de l&#8217;\u00e9tat pr\u00e9c\u00e9dent dans un fichier nomm\u00e9 cette fois-\u00e7i <span class=\"file-color\"><em>terraform.tfstate.backup<\/em> avant d&#8217;apporter les modifications au fichier d&#8217;\u00e9tat courant <em>terraform.tfstate.<\/em><\/span><\/p>\n<p>Cet \u00e9tat est donc tr\u00e8s important et nous allons voir dans cet article comment l&#8217;externaliser sur un bucket (compartiment) S3 via la notion de <em>remote backend <\/em>afin de le rendre disponible \u00e0 chacun tout en le pr\u00e9servant d&#8217;une perte accidentelle. Nous utiliserons \u00e9galement une table<em> DynamoDB qui <\/em>servira \u00e0 verrouiller le fichier en \u00e9criture afin d&#8217;\u00e9viter un acc\u00e8s concurrentiel; c&#8217;est-\u00e0-dire que plusieurs process\/personnes ne puissent pas apporter des modifications au m\u00eame moment \u00e0 votre infrastructure. En effet il est vital avant chaque ex\u00e9cution, de s&#8217;assurer de bien disposer des derni\u00e8res donn\u00e9es d&#8217;\u00e9tat et d&#8217;\u00eatre le seul \u00e0 y apporter des modifications \u00e0 l&#8217;instant T. C&#8217;est pourquoi le stockage centralis\u00e9 s&#8217;impose et choisir le service AWS S3 offre plusieurs fonctionnalit\u00e9s int\u00e9ressantes.<\/p>\n<p>A noter qu&#8217;en environnement DevOps il est primordial d&#8217;\u00e9viter tant que faire se peut la d\u00e9duplication de son code, l&#8217;on va donc s&#8217;int\u00e9resser \u00e0 la fonctionnalit\u00e9 des <em>Workspaces<\/em>.<\/p>\n<h2><span style=\"text-decoration: underline;\"><span style=\"color: #ff0000; text-decoration: underline;\"><em><strong>II] Contexte:<\/strong><\/em><\/span><\/span><\/h2>\n<p>Notre objectif ici est de proposer une solution permettant d&#8217;automatiser la cr\u00e9ation\\mise \u00e0 jour\\suppression d&#8217;une instance EC2 dans un environnement bac \u00e0 sable AWS. Les objets de type VPC, subnet, security group seront d\u00e9j\u00e0 provisionn\u00e9s.\u00a0 Pour l&#8217;instant cela reste simple et votre code terraform pourrait alors ressembler \u00e0 ceci:<\/p>\n<pre class=\"brush: yaml; title: ; notranslate\" title=\"\">terraform {\r\n required_providers {\r\n  aws = {\r\n   source = &quot;hashicorp\/aws&quot;\r\n   version = &quot;~&gt; 4.0&quot;\r\n  }\r\n }\r\n}\r\nprovider &quot;aws&quot; {\r\n region = var.AWS_REGION\r\n access_key = var.AWS_ACCESS_KEY\r\n secret_key = var.AWS_SECRET_KEY\r\n}\r\n\r\nresource &quot;aws_instance&quot; &quot;mon_ec2&quot;{        # Nom que l'on donne \u00e0 notre ressource pour terraform (\u00e0 ne pas confondre avec le tag Name de l'EC2)\r\n ami = var.AMI\r\n instance_type = var.INSTANCE_TYPE\r\n tags = {\r\n  Name = &quot;${var.TAG_NAME}&quot;\r\n  AUTEUR = &quot;${var.TAG_AUTEUR}&quot;\r\n  DESCRIPTION = &quot;${var.TAG_DESCRIPTION}&quot;\r\n  ENVIRONNEMENT = &quot;${var.TAG_ENVIRONNEMENT}&quot;\r\n }\r\n key_name = var.KEY_NAME\r\n subnet_id = var.SUBNET_ID\r\n vpc_security_group_ids = var.VPC_SECURITY_GROUP_IDS\r\n disable_api_termination = true\r\n}\r\n\r\n<\/pre>\n<p>On d\u00e9finit notre provider AWS, et l&#8217;on renseigne nos param\u00e8tres d&#8217;identification (inutile si vous avez d\u00e9ploy\u00e9 AWS CLI et fait un aws configure ou mieux que vous utilisiez un r\u00f4le IAM). Ensuite on d\u00e9fini une ressource de type &#8220;aws_instance&#8221; (=EC2) que l&#8217;on nommera pour terraform &#8220;mon_ec2&#8221;<\/p>\n<p>On constate qu&#8217;un certain nombre de param\u00e8tres sont naturellement variabilis\u00e9s via les fichiers <em>variables.tf et terraform.auto.tfvars<\/em>. Notamment pour l&#8217;identifiant de l&#8217;AMI \u00e0 utiliser, le type d&#8217;instance (ex:T2.micro) ainsi que la g\u00e9n\u00e9ration de certains tags etc. Il n&#8217;y a plus qu&#8217;\u00e0 ex\u00e9cuter notre code terraform via les commandes <em>terraform plan<\/em> pour afficher dans un premier temps le plan d&#8217;action puis un <em>terraform apply<\/em> pour cr\u00e9er la ressource de type instance EC2 sur notre environnement AWS.<\/p>\n<p><a href=\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/01TerraformApply.jpg\" target=\"_blank\" rel=\"noopener\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-9789 size-full\" src=\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/01TerraformApply.jpg\" alt=\"\" width=\"687\" height=\"695\" srcset=\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/01TerraformApply.jpg 687w, https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/01TerraformApply-297x300.jpg 297w, https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/01TerraformApply-50x50.jpg 50w\" sizes=\"auto, (max-width: 687px) 100vw, 687px\" \/><\/a><\/p>\n<p>Sans surprise notre EC2 a bien \u00e9t\u00e9 cr\u00e9\u00e9e.<\/p>\n<p>Les jours passent et je voudrais \u00e0 nouveau cr\u00e9er une EC2 de la m\u00eame mani\u00e8re mais \u00e0 partir d&#8217;une nouvelle AMI. J&#8217;effectue alors quelques modifications au niveau de mes variables pour changer la valeur de var.AMI (ami-09155d2e27d9fb18c) ainsi que var.Name (EC2_TESTLPRTERRAFORM_EC2_<strong>2<\/strong>) puis j&#8217;ex\u00e9cute \u00e0 nouveau mon code en esp\u00e9rant avoir une deuxi\u00e8me EC2 !<\/p>\n<p>Et l\u00e0 vous l&#8217;aurez compris terraform \u00e9tant stateful, il d\u00e9tecte qu&#8217;il a d\u00e9j\u00e0 cr\u00e9\u00e9 une ressource nomm\u00e9e dans le code terraform <strong>&#8220;aws_instance&#8221; &#8220;mon_ec2&#8221;<\/strong> via son fichier<em> terraform.tfstate<\/em> et me propose de la <strong>d\u00e9truire <\/strong>(1 to destroy) pour en <strong>ajouter une nouvelle<\/strong> (1 to add) \u00e0 partir cette fois d&#8217;une autre image AMI et de changer le tag <em>Name<\/em> au passage (c&#8217;est bien le changement d&#8217;AMI qui explique la destruction puis recr\u00e9ation et pas le changement de tag <em>Name)<\/em> !<\/p>\n<p><a href=\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/02TerraformApply.jpg\" target=\"_blank\" rel=\"noopener\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-9793 size-full\" src=\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/02TerraformApply.jpg\" alt=\"\" width=\"787\" height=\"291\" srcset=\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/02TerraformApply.jpg 787w, https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/02TerraformApply-300x111.jpg 300w, https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/02TerraformApply-768x284.jpg 768w\" sizes=\"auto, (max-width: 787px) 100vw, 787px\" \/><\/a><\/p>\n<p>Ce comportement est tout \u00e0 fait normal car c&#8217;est la philosophie m\u00eame de Terraform. Malheureusement nous ne souhaitons en aucun cas supprimer l&#8217;EC2 pr\u00e9c\u00e9demment cr\u00e9\u00e9e.<br \/>\nLa question est donc de trouver le moyen <strong>de r\u00e9ex\u00e9cuter ce m\u00eame code <\/strong>(un nombre ind\u00e9fini de fois d&#8217;ailleurs) pour obtenir une nouvelle EC2 \u00e0 chaque fois mais sans toucher aux autres pr\u00e9c\u00e9demment cr\u00e9\u00e9es et tout en garantissant l&#8217;int\u00e9grit\u00e9 du fichier<em> terraform.tfstate<\/em> qui pour l&#8217;instant est stock\u00e9 en local.<\/p>\n<p>A noter qu&#8217;il est inutile d&#8217;essayer de variabiliser le nom de la ressource Terraform afin d&#8217;esp\u00e9rer arriver \u00e0 vos fins, ce n&#8217;est pas possible.<\/p>\n<pre class=\"brush: yaml; title: ; notranslate\" title=\"\">\r\n# Ne fonctionne pas !\r\nresource &quot;aws_instance&quot; &quot;${var.RESOURCE_NAME}&quot; {\r\n [...]\r\n}<\/pre>\n<h2><span style=\"text-decoration: underline;\"><span style=\"color: #ff0000; text-decoration: underline;\"><em><strong>III] Pr\u00e9requis:<\/strong><\/em><\/span><\/span><\/h2>\n<ul>\n<li>Les binaires <a href=\"https:\/\/developer.hashicorp.com\/terraform\/downloads\">Terraform CLI (1.3.7)<\/a><\/li>\n<li>Les binaires <a href=\"https:\/\/aws.amazon.com\/fr\/cli\/\">AWS CLI (2.9.18)<\/a><\/li>\n<li>1 <a href=\"https:\/\/aws.amazon.com\/fr\/s3\/\">Bucket S3<\/a> (pour centraliser les fichiers d&#8217;\u00e9tat)<\/li>\n<li>1 <a href=\"https:\/\/aws.amazon.com\/fr\/dynamodb\/\">Table dynamoDB<\/a> (pour gerer les verrous sur les fichiers d&#8217;\u00e9tat)<\/li>\n<\/ul>\n<h2><span style=\"text-decoration: underline;\"><span style=\"color: #ff0000; text-decoration: underline;\"><em><strong>IV] &#8220;Arborescence&#8221; Terraform actuelle:<\/strong><\/em><\/span><\/span><\/h2>\n<p><a href=\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/Arborescence-Actuelle.jpg\" target=\"_blank\" rel=\"noopener\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-9980 size-full\" src=\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/Arborescence-Actuelle.jpg\" alt=\"\" width=\"1267\" height=\"732\" srcset=\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/Arborescence-Actuelle.jpg 1267w, https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/Arborescence-Actuelle-300x173.jpg 300w, https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/Arborescence-Actuelle-1024x592.jpg 1024w, https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/Arborescence-Actuelle-768x444.jpg 768w\" sizes=\"auto, (max-width: 1267px) 100vw, 1267px\" \/><\/a><\/p>\n<h2><span style=\"text-decoration: underline;\"><span style=\"color: #ff0000; text-decoration: underline;\"><em><strong>IV] &#8220;Arborescence&#8221; Terraform cible:<\/strong><\/em><\/span><\/span><\/h2>\n<p><a href=\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/Arborescence-cible.jpg\" target=\"_blank\" rel=\"noopener\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-9981 size-full\" src=\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/Arborescence-cible.jpg\" alt=\"\" width=\"804\" height=\"331\" srcset=\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/Arborescence-cible.jpg 804w, https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/Arborescence-cible-300x124.jpg 300w, https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/Arborescence-cible-768x316.jpg 768w\" sizes=\"auto, (max-width: 804px) 100vw, 804px\" \/><\/a><\/p>\n<p>L&#8217;une des approches nous permettant de r\u00e9ex\u00e9cuter exactement <strong>l<\/strong><strong>e m\u00eame code Terraform<\/strong> (moyennant naturellement le changement de nos variables) pour g\u00e9rer des ressources diff\u00e9rentes est d&#8217;utiliser la fonctionnalit\u00e9 <em>Workspaces <\/em>de Terraform<em>.<br \/>\n<\/em>Ces derniers permettent en effet de g\u00e9n\u00e9rer des fichiers d&#8217;\u00e9tats (<em>terraform.tfstate<\/em>) diff\u00e9rents pour un m\u00eame code d&#8217;ex\u00e9cution Terraform en les rangeant par <em>Workspaces<\/em>. C&#8217;est-\u00e0-dire qu&#8217;il suffira avant chaque ex\u00e9cution de notre m\u00eame code de se positionner sur un nouveau <em>Workspace<\/em> afin d&#8217;obtenir des fichiers d&#8217;\u00e9tat distinctes. De cette mani\u00e8re Terraform pourra g\u00e9rer plusieurs ensembles de ressources qui n&#8217;interf\u00e8rent pas entre elles. C&#8217;est exactement ce qu&#8217;on l&#8217;on souhaite faire. Une m\u00eame configuration Terraform pour &#8220;n&#8221; fichiers d&#8217;\u00e9tats !<\/p>\n<p><strong>Petite apart\u00e9:<\/strong><br \/>\nDans mes lectures j&#8217;ai souvent constat\u00e9 que cette fonctionnalit\u00e9 \u00e9tait utilis\u00e9e pour dupliquer des environnements. Par exemple un m\u00eame fichier main.tf pouvant \u00eatre jou\u00e9 dans un <em>Workspace <\/em>nomm\u00e9 &#8220;Developpement&#8221; afin de r\u00e9aliser des tests puis ensuite jou\u00e9 dans un autre <em>Workspace<\/em> nomm\u00e9 cette fois &#8220;Production&#8221;. Passer d&#8217;un <em>Workspace<\/em> \u00e0 l&#8217;autre tout en jouant sur nos variables permet alors d&#8217;obtenir deux environnements diff\u00e9rents mais \u00e0 partir <span style=\"color: #000000;\">du m\u00eame code<\/span> terraform. En effet un seul fichier <em>main.tf<\/em> sera utilis\u00e9 pour g\u00e9n\u00e9rer ici deux fichiers <em>terraform.tfstate<\/em>, un pour chacun des W<em>orkspaces<\/em>.<\/p>\n<p><strong><span style=\"color: #ff0000;\"><em><span style=\"text-decoration: underline;\">Attention toutefois la documentation Terraform est assez claire \u00e0 ce sujet:<\/span><\/em><\/span><\/strong><\/p>\n<p><a href=\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/Using-Workspace.jpg\" target=\"_blank\" rel=\"noopener\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-9810 size-full\" src=\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/Using-Workspace.jpg\" alt=\"\" width=\"711\" height=\"200\" srcset=\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/Using-Workspace.jpg 711w, https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/Using-Workspace-300x84.jpg 300w\" sizes=\"auto, (max-width: 711px) 100vw, 711px\" \/><\/a><\/p>\n<p style=\"text-align: center;\"><a href=\"https:\/\/developer.hashicorp.com\/terraform\/language\/state\/workspaces\">https:\/\/developer.hashicorp.com\/terraform\/language\/state\/workspaces<\/a><br \/>\n<a href=\"https:\/\/developer.hashicorp.com\/terraform\/cli\/workspaces#use-cases\">https:\/\/developer.hashicorp.com\/terraform\/cli\/workspaces#use-cases<\/a><\/p>\n<p>Hashicorp nous explique alors qu&#8217;opter pour la fonctionnalit\u00e9 <em>Workspaces <\/em>pour g\u00e9rer nos diff\u00e9rents environnements Production \/ Qualification \/ D\u00e9veloppement peut poser un probl\u00e8me &#8220;d&#8217;isolation&#8221;. En effet utiliser le m\u00eame code terraform au sein de diff\u00e9rents <em>Workspaces<\/em> implique de n&#8217;utiliser qu&#8217;un seul <em>backend S3<\/em> (= <em>bucket S3).<\/em> Au niveau du sch\u00e9ma &#8220;IV] Architecture cible&#8221;, on constate bien que l&#8217;int\u00e9gralit\u00e9 de nos fichiers <em>terraform.tfstate<\/em> correspondant \u00e0 chacun de nos <em>Workspaces<\/em> (=environnements de production, qualification et d\u00e9veloppement) vont se retrouver au m\u00eame endroit. Il n&#8217;y a donc aucune s\u00e9paration au niveau stockage S3.<\/p>\n<p>Si vos contraintes en terme de s\u00e9curit\u00e9 ne sont pas trop \u00e9lev\u00e9es cela me semble tout \u00e0 fait jouable sinon il faudra se pencher sur une gestion via par exemple l&#8217;utilisation de diff\u00e9rentes branches <em>GIT<\/em>\u00a0 (avec malheureusement d\u00e9duplication de votre code qui devra \u00eatre maintenu \u00e0 jour entre les diff\u00e9rentes branches&#8230;) ou alors \u00e9ventuellement utiliser un autre outil nomm\u00e9 <a href=\"https:\/\/terragrunt.gruntwork.io\/\"><em>Terragrunt <\/em><\/a>(wrapper pour terraform) \u00e9vitant justement la d\u00e9duplication de code.<\/p>\n<h2><span style=\"text-decoration: underline; color: #ff0000;\"><em><strong>V] Mise en oeuvre:<\/strong><\/em><\/span><\/h2>\n<p>Passons \u00e0 la mise en \u0153uvre afin d&#8217;illustrer le concept:<\/p>\n<h3><span style=\"color: #000080;\">A- Commen\u00e7ons par cr\u00e9er notre <em>bucket S3<\/em> qui va h\u00e9berger l&#8217;ensemble de nos fichiers d&#8217;\u00e9tats (<em>terraform.tfstate<\/em>):<\/span><\/h3>\n<pre># Consultation de l'aide de la commande create-bucket\r\nC:\\Users\\lprou>aws s3api create-bucket help\r\n\r\n# Cr\u00e9ation du compartiment S3\r\nC:\\Users\\lprou>aws s3api create-bucket --bucket capdata-tfstate --region eu-west-3 --create-bucket-configuration LocationConstraint=eu-west-3 --acl private\r\n\r\n# D\u00e9sactivation de l'acc\u00e8s publique\r\nC:\\Users\\lprou>aws s3api put-public-access-block --bucket capdata-tfstate --public-access-block-configuration \"BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true\"\r\n\r\n# Activation du chiffrage\r\nC:\\Users\\lprou>aws s3api put-bucket-encryption --bucket capdata-tfstate --server-side-encryption-configuration \"{\\\"Rules\\\": [{\\\"ApplyServerSideEncryptionByDefault\\\":{\\\"SSEAlgorithm\\\": \\\"AES256\\\"}}]}\"\r\n\r\n# Activation du versionning afin de conserver un historique de nos fichiers terraform.tfstate\r\nC:\\Users\\lprou>aws s3api put-bucket-versioning --bucket capdata-tfstate --versioning-configuration MFADelete=Disabled,Status=Enabled\r\n<\/pre>\n<p>Terraform aura besoin des droits suivants sur le bucket S3 (cf <a href=\"https:\/\/developer.hashicorp.com\/terraform\/language\/settings\/backends\/s3\">S3 Bucket Permissions<\/a>):<br \/>\ns3:ListBucket<br \/>\ns3:GetObject<br \/>\ns3:PutObject<br \/>\ns3:DeleteObject<\/p>\n<p>A noter qu&#8217;il est possible en environnement critique d&#8217;activer la r\u00e9plication de votre bucket S3:<br \/>\n<a href=\"https:\/\/docs.aws.amazon.com\/fr_fr\/AmazonS3\/latest\/userguide\/replication.html\">https:\/\/docs.aws.amazon.com\/fr_fr\/AmazonS3\/latest\/userguide\/replication.html<\/a><br \/>\nEt \u00e9galement de mettre en place une r\u00e8gle de cycle de vie pour faire du m\u00e9nage concernant les anciennes versions de vos fichiers terraform.tstate: <a href=\"https:\/\/docs.aws.amazon.com\/fr_fr\/AmazonS3\/latest\/userguide\/object-lifecycle-mgmt.html\">https:\/\/docs.aws.amazon.com\/fr_fr\/AmazonS3\/latest\/userguide\/object-lifecycle-mgmt.html<\/a><\/p>\n<h3><span style=\"color: #000080;\">B- Continuons par cr\u00e9er notre table DynamoDB qui h\u00e9bergera les informations de verrouillage des fichiers terraform.tfstate:<\/span><\/h3>\n<pre># Consultation de l'aide de la commande create-table\r\nC:\\Users\\lprou>aws dynamodb create-table help\r\n\r\n# Cr\u00e9ation d'une table DynamoDB\r\nC:\\Users\\lprou>aws dynamodb create-table --table-name capdata-terraform-tfstate --attribute-definitions AttributeName=LockID,AttributeType=S --key-schema AttributeName=LockID,KeyType=HASH --provisioned-throughput ReadCapacityUnits=1,WriteCapacityUnits=1 --table-class STANDARD\r\n\r\n# Configuration des capacit\u00e9s d'autoscaling en \u00e9criture\r\nC:\\Users\\lprou>aws application-autoscaling register-scalable-target --service-namespace dynamodb --scalable-dimension dynamodb:table:WriteCapacityUnits --resource-id table\/capdata-terraform-tfstate --min-capacity 1 --max-capacity 10\r\n\r\n# Configuration des capacit\u00e9s d'autoscaling en lecture\r\nC:\\Users\\lprou>aws application-autoscaling register-scalable-target --service-namespace dynamodb --scalable-dimension dynamodb:table:ReadCapacityUnits --resource-id table\/capdata-terraform-tfstate --min-capacity 1 --max-capacity 10<\/pre>\n<p>Terraform aura besoin des droits suivants table DynamoDB (cf <a href=\"https:\/\/developer.hashicorp.com\/terraform\/language\/settings\/backends\/s3\">DynamoDB Table Permissions<\/a>):<br \/>\ndynamodb:DescribeTable<br \/>\ndynamodb:GetItem<br \/>\ndynamodb:PutItem<br \/>\ndynamodb:DeleteItem<\/p>\n<h3><span style=\"color: #003366;\">C- Cr\u00e9ation de notre environnement terraform dans notre dossier &#8220;ProjectCreateEC2&#8221;:<\/span><\/h3>\n<p>Comme vu un peu plus haut nous disposons d&#8217;un dossier nomm\u00e9 c:\\temp\\ProjectCreateEC2 avec les fichiers suivants:<\/p>\n<p><a href=\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/tree.jpg\" target=\"_blank\" rel=\"noopener\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-9846 size-full\" src=\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/tree.jpg\" alt=\"\" width=\"484\" height=\"173\" srcset=\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/tree.jpg 484w, https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/tree-300x107.jpg 300w\" sizes=\"auto, (max-width: 484px) 100vw, 484px\" \/><\/a><\/p>\n<div><\/div>\n<div><\/div>\n<div>La premi\u00e8re chose \u00e0 faire par rapport \u00e0 notre fichier main.tf initial (vu dans la partie II] Contexte) est d&#8217;ajouter notre remote backend pour le faire pointer sur notre bucket S3 pr\u00e9c\u00e9demment cr\u00e9\u00e9 et utiliser notre table DynamoDB. Ce qui donne ceci:<\/div>\n<div><\/div>\n<div>\n<pre class=\"brush: yaml; title: ; notranslate\" title=\"\">terraform {\r\n required_providers {\r\n  aws = {\r\n   source = &quot;hashicorp\/aws&quot;\r\n   version = &quot;~&gt; 4.0&quot;\r\n  }\r\n }\r\n}\r\n\r\nprovider &quot;aws&quot; {\r\n region = var.AWS_REGION\r\n access_key = var.AWS_ACCESS_KEY\r\n secret_key = var.AWS_SECRET_KEY\r\n }\r\n\r\nterraform {\r\n backend &quot;s3&quot; {\r\n  bucket = &quot;capdata-tfstate&quot;                    # nom de notre bucket S3\r\n  key = &quot;terraform.tfstate&quot;                     # nom \u00e0 utiliser pour les fichiers d'\u00e9tats\r\n  region = &quot;eu-west-3&quot;\r\n  encrypt = true                                # param\u00e8tre optionnel et je pense inutile ici puisque l'encryption \u00e0 d\u00e9j\u00e0 \u00e9t\u00e9 positionn\u00e9 sur notre bucket \r\n  dynamodb_table = &quot;capdata-terraform-tfstate&quot;  # nom de notre table DynamoDB\r\n }\r\n}\r\n\r\nresource &quot;aws_instance&quot; &quot;mon_ec2&quot; {\r\n ami = var.AMI\r\n instance_type = var.INSTANCE_TYPE\r\n tags = {\r\n  Name = &quot;${var.TAG_NAME}&quot;\r\n  AUTEUR = &quot;${var.TAG_AUTEUR}&quot;\r\n  DESCRIPTION = &quot;${var.TAG_DESCRIPTION}&quot;\r\n  ENVIRONNEMENT = &quot;${var.TAG_ENVIRONNEMENT}&quot;\r\n }\r\n key_name = var.KEY_NAME\r\n subnet_id = var.SUBNET_ID\r\n vpc_security_group_ids = var.VPC_SECURITY_GROUP_IDS\r\n disable_api_termination = true\r\n}<\/pre>\n<\/div>\n<p>Je n&#8217;aborderai pas en d\u00e9tail le contenu des autres fichiers mais sachez que:<br \/>\n&#8211; terraform.auto.tfvars contient les identifiants AWS<br \/>\n&#8211; variables.tf contient les autres variables<br \/>\n&#8211; output.tf sert \u00e0 renvoyer des param\u00e8tres de sortie (ex: Adresse IP de l&#8217;EC2 cr\u00e9\u00e9e&#8230;)suite \u00e0 l&#8217;ex\u00e9cution de notre code Terraform. Nous avons ainsi la possibilit\u00e9 d&#8217;interroger les valeurs d&#8217;output pr\u00e9sentes dans notre <em>tfstate<\/em> via la commande:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\n# Affiche l'aide concernant la commande output\r\nC:\\temp\\ProjectCreateEC2&gt;terraform output --help           \r\n\r\n# R\u00e9cup\u00e8re uniquement la valeur de l'output nomm\u00e9 private_ip\r\nC:\\temp\\ProjectCreateEC2&gt;terraform output -raw private_ip         \r\n172.44.2.118\r\n\r\n# R\u00e9cup\u00e8re tout l'output au format json\r\nC:\\temp\\ProjectCreateEC2&gt;terraform output -json                   \r\n{\r\n &quot;ami&quot;: {\r\n  &quot;sensitive&quot;: false,\r\n  &quot;type&quot;: &quot;string&quot;,\r\n  &quot;value&quot;: &quot;ami-01e9b120b1e5c5004&quot;\r\n },\r\n &quot;id&quot;: {\r\n  &quot;sensitive&quot;: false,\r\n  &quot;type&quot;: &quot;string&quot;,\r\n  &quot;value&quot;: &quot;i-0a572194708a33c46&quot;\r\n }, [...]<\/pre>\n<p>Une fois la modification effectu\u00e9e il faut r\u00e9initialiser notre dossier de travail Terraform ProjectCreateEC2 afin qu&#8217;il puisse prendre en compte notre remote backend, sinon vous obtiendrai l&#8217;erreur suivante:<\/p>\n<p><a href=\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/InitRequired.jpg\" target=\"_blank\" rel=\"noopener\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-9852 size-full\" src=\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/InitRequired.jpg\" alt=\"\" width=\"662\" height=\"308\" srcset=\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/InitRequired.jpg 662w, https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/InitRequired-300x140.jpg 300w\" sizes=\"auto, (max-width: 662px) 100vw, 662px\" \/><\/a><\/p>\n<p>En effet un <em>terraform init <\/em>est obligatoire \u00e0 chaque changement au niveau du provider, backend ou modules.<br \/>\nIl nous explique alors qu&#8217;il est possible de jouer avec la commande <em>terraform init -reconfigure<\/em> ou <em>-migrate-state<\/em>.<\/p>\n<p>Vous pouvez \u00e9galement vous contentez de faire du m\u00e9nage dans le dossier c:\\temp\\ProjectCreateEC2 en supprimant le dossier .terraform qui contient les informations d&#8217;initialisation ainsi qu&#8217;en supprimant le fichier .terraform.lock.hcl. Ce dernier permet justement \u00e0 Terraform de suivre les modifications apport\u00e9es au provider, backend et ou modules afin de demander une r\u00e9initialisation lors de la prochaine ex\u00e9cution.<br \/>\nJe vous invite vivement \u00e0 parcourir ce dossier et ouvrir les fichiers qu&#8217;il contient afin de comprendre le fonctionnement interne de Terraform ;).<\/p>\n<p>Une fois le m\u00e9nage effectu\u00e9, je lance donc une nouvelle initialisation de mon dossier c:\\temp\\ProjectCreateEC2 (cette manipulation \u00e9quivaut donc \u00e0 la commande <em>terraform init -reconfigure<\/em>):<\/p>\n<p><a href=\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/init.jpg\" target=\"_blank\" rel=\"noopener\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-9854 size-full\" src=\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/init.jpg\" alt=\"\" width=\"659\" height=\"424\" srcset=\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/init.jpg 659w, https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/init-300x193.jpg 300w\" sizes=\"auto, (max-width: 659px) 100vw, 659px\" \/><\/a><\/p>\n<p>L&#8217;initialisation est termin\u00e9e et notre dossier ressemble d\u00e9sormais \u00e0 cela:<\/p>\n<p><a href=\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/tree2.jpg\" target=\"_blank\" rel=\"noopener\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-9855 size-full\" src=\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/tree2.jpg\" alt=\"\" width=\"595\" height=\"330\" srcset=\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/tree2.jpg 595w, https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/tree2-300x166.jpg 300w\" sizes=\"auto, (max-width: 595px) 100vw, 595px\" \/><\/a><\/p>\n<p>On constate que le fichier d&#8217;\u00e9tat n&#8217;est plus \u00e0 la racine de notre dossier ProjectCreateEC2 mais dans le dossier d&#8217;initialisation .terraform\\terraform.tfstate.<br \/>\nCela semble \u00e9tonnant car le but est de le d\u00e9porter sur notre bucket S3 et surtout que nous n&#8217;avons toujours pas cr\u00e9er notre ressource <em><strong>&#8220;aws_instance&#8221; &#8220;mon_ec2&#8221;<\/strong><\/em><span style=\"color: #000000;\">\u00a0 via la commande<em> terraform apply<\/em>. <\/span>Donc logiquement aucun fichier d&#8217;\u00e9tat ne devrait-\u00eatre cr\u00e9\u00e9 ! Ouvrons le pour voir ce qu&#8217;il contient:<\/p>\n<pre class=\"brush: yaml; title: ; notranslate\" title=\"\">\r\n{\r\n &quot;version&quot;: 3,\r\n &quot;serial&quot;: 1,\r\n &quot;lineage&quot;: &quot;0fbafb73-0882-e174-7f75-cfc706d29c5e&quot;,\r\n &quot;backend&quot;: {\r\n  &quot;type&quot;: &quot;s3&quot;,                                                         # Il s'agit d'un stockage de type S3\r\n  &quot;config&quot;: {\r\n   &quot;access_key&quot;: null,\r\n   &quot;acl&quot;: null,\r\n   &quot;assume_role_duration_seconds&quot;: null,\r\n   &quot;assume_role_policy&quot;: null,\r\n   &quot;assume_role_policy_arns&quot;: null,\r\n   &quot;assume_role_tags&quot;: null,\r\n   &quot;assume_role_transitive_tag_keys&quot;: null,\r\n   &quot;bucket&quot;: &quot;capdata-made-tfstate&quot;,                                    # On retrouve le nom de notre bucket S3\r\n   &quot;dynamodb_endpoint&quot;: null,\r\n   &quot;dynamodb_table&quot;: &quot;terraform_tfstate&quot;,                               # On retrouve le nom de notre table DynamoDB\r\n   &quot;encrypt&quot;: true,\r\n   &quot;endpoint&quot;: null,\r\n   &quot;external_id&quot;: null,\r\n   &quot;force_path_style&quot;: null,\r\n   &quot;iam_endpoint&quot;: null,\r\n   &quot;key&quot;: &quot;terraform.tfstate&quot;,                                          # Le nom du fichier tfstate\r\n   &quot;kms_key_id&quot;: null,\r\n   &quot;max_retries&quot;: null,\r\n   &quot;profile&quot;: null,\r\n   &quot;region&quot;: &quot;eu-west-3&quot;,\r\n   &quot;role_arn&quot;: null,\r\n   &quot;secret_key&quot;: null,\r\n   &quot;session_name&quot;: null,\r\n   &quot;shared_credentials_file&quot;: null,\r\n   &quot;skip_credentials_validation&quot;: null,\r\n   &quot;skip_metadata_api_check&quot;: null,\r\n   &quot;skip_region_validation&quot;: null,\r\n   &quot;sse_customer_key&quot;: null,\r\n   &quot;sts_endpoint&quot;: null,\r\n   &quot;token&quot;: null,\r\n   &quot;workspace_key_prefix&quot;: null\r\n  },\r\n  &quot;hash&quot;: 3248788392\r\n },\r\n &quot;modules&quot;: [\r\n {\r\n  &quot;path&quot;: [\r\n  &quot;root&quot;\r\n  ],\r\n  &quot;outputs&quot;: {},\r\n  &quot;resources&quot;: {},\r\n  &quot;depends_on&quot;: []\r\n }\r\n ]\r\n}<\/pre>\n<p>On se rend compte qu&#8217;il ne s&#8217;agit pas l\u00e0 d&#8217;un \u00e9tat \u00e0 proprement parler mais bien de toutes les informations n\u00e9cessaires \u00e0 Terraform pour externaliser les futurs fichiers<em> terraform.tfstate<\/em> sur notre bucket S3 et utiliser notre table DynamoDB.<\/p>\n<h3><span style=\"color: #003366;\">D- Cr\u00e9ation de nos <em>Workspaces<\/em>:<\/span><\/h3>\n<p>Il faut donc maintenant s&#8217;int\u00e9resser \u00e0 la cr\u00e9ation d&#8217;un <em>Workspace<\/em> avant d&#8217;ex\u00e9cuter notre code qui instanciera notre premi\u00e8re instance EC2.<br \/>\nPour s&#8217;y retrouver j&#8217;affecte comme nom de <em>Workspace<\/em> la m\u00eame valeur que mon tag &#8220;Name&#8221; (qui lui est variabilis\u00e9 dans la ressource terraform) de ma future EC2. Une fois cr\u00e9\u00e9 Terraform bascule automatiquement sur notre nouveau <em>Workspace<\/em> (pr\u00e9sence d&#8217;un * en face du <em>workspace<\/em> courant dans la commande list).<\/p>\n<pre>C:\\temp\\ProjectCreateEC2>terraform workspace new EC2_TESTLPRTERRAFORM_EC2_1\r\n<strong><span style=\"color: #99cc00;\">Created and switched to workspace \"EC2_TESTLPRTERRAFORM_EC2_1\"!            <\/span><\/strong><span style=\"color: #ff0000;\"># On bascule du <em>Workspace<\/em> par d\u00e9faut \u00e0 celui nouvellement cr\u00e9\u00e9<\/span>\r\n\r\n<span style=\"color: #99cc00;\">You're now on a new, empty workspace. Workspaces isolate their state,<\/span>\r\n<span style=\"color: #99cc00;\">so if you run \"terraform plan\" Terraform will not see any existing state<\/span>\r\n<span style=\"color: #99cc00;\">for this configuration.<\/span>\r\n\r\nC:\\temp\\ProjectCreateEC2>terraform workspace list\r\ndefault\r\n* EC2_TESTLPRTERRAFORM_EC2_1<\/pre>\n<p>Nous sommes donc positionn\u00e9 sur le <em>Workspace<\/em> EC2_TESTLPRTERRAFORM_EC2_1 et pouvons d\u00e9sormais ex\u00e9cuter notre code d&#8217;instanciation d&#8217;EC2 (enfin !)<\/p>\n<pre>C:\\temp\\ProjectCreateEC2>terraform apply\r\n\r\nTerraform used the selected providers to generate the following execution plan. Resource actions are indicated with the\r\nfollowing symbols:\r\n<span style=\"color: #99cc00;\">+<\/span> create\r\n\r\nTerraform will perform the following actions:\r\n\r\n# aws_instance.mon_ec2 will be created\r\n<span style=\"color: #99cc00;\">+<\/span> resource \"aws_instance\" \"mon_ec2\" {\r\n<span style=\"color: #99cc00;\">+<\/span> ami = \"ami-01e9b120b1e5c5004\"\r\n<span style=\"color: #99cc00;\">+<\/span> arn = (known after apply)\r\n<span style=\"color: #99cc00;\">+<\/span> associate_public_ip_address = (known after apply)\r\n<span style=\"color: #99cc00;\">+<\/span> availability_zone = (known after apply)\r\n<span style=\"color: #99cc00;\">+<\/span> cpu_core_count = (known after apply)\r\n[...]\r\n\r\nPlan: 1 to add, 0 to change, 0 to destroy.                                       <span style=\"color: #ff0000;\"># Il s'agit bien d'un ajout.<\/span>\r\n\r\nChanges to Outputs:\r\n<span style=\"color: #99cc00;\">+<\/span> ami = \"ami-01e9b120b1e5c5004\"\r\n<span style=\"color: #99cc00;\">+<\/span> id = (known after apply)\r\n<span style=\"color: #99cc00;\">+<\/span> instance_type = \"t2.micro\"\r\n<span style=\"color: #99cc00;\">+<\/span> private_ip = (known after apply)\r\n<span style=\"color: #99cc00;\">+<\/span> tag_Name = \"EC2_TESTLPRTERRAFORM_EC2_1\"\r\n<span style=\"color: #99cc00;\">+<\/span> tags = {\r\n<span style=\"color: #99cc00;\">+<\/span> \"AUTEUR\" = \"LPR\"\r\n<span style=\"color: #99cc00;\">+<\/span> \"DESCRIPTION\" = \"EC2 CREEE DEPUIS TERRAFORM\"\r\n<span style=\"color: #99cc00;\">+<\/span> \"ENVIRONNEMENT\" = \"TEST_TERRAFORM\"\r\n<span style=\"color: #99cc00;\">+<\/span> \"Name\" = \"EC2_TESTLPRTERRAFORM_EC2_1\"\r\n}\r\n\r\n<strong>Do you want to perform these actions in workspace \"EC2_TESTLPRTERRAFORM_EC2_1\"?  <\/strong><span style=\"color: #ff0000;\"># Terraform est plut\u00f4t sympas il nous confirme le Workspace<\/span>\r\nTerraform will perform the actions described above.                                <span style=\"color: #ff0000;\">sur lequel il va lancer les actions.<\/span>\r\nOnly 'yes' will be accepted to approve.\r\n\r\nEnter a value: yes\r\n\r\naws_instance.mon_ec2: Creating...\r\naws_instance.mon_ec2: Still creating... [10s elapsed]\r\naws_instance.mon_ec2: Still creating... [20s elapsed]\r\naws_instance.mon_ec2: Still creating... [30s elapsed]\r\naws_instance.mon_ec2: Creation complete after 32s [id=i-0a14f7ff418babb3c]\r\n\r\n<strong><span style=\"color: #99cc00;\">Apply complete! Resources: 1 added, 0 changed, 0 destroyed.                      <\/span><\/strong><span style=\"color: #99cc00;\"><span style=\"color: #ff0000;\"># l'ajout est termin\u00e9 !<\/span><\/span><strong><span style=\"color: #99cc00;\">\r\n\r\nOutputs:                                                                         <\/span><\/strong><span style=\"color: #99cc00;\"><span style=\"color: #ff0000;\"># Affichage des variables de sortie comme vu dans la partie C-<\/span><\/span>\r\n\r\nami = \"ami-01e9b120b1e5c5004\"\r\nid = \"i-0a14f7ff418babb3c\"\r\ninstance_type = \"t2.micro\"\r\nprivate_ip = \"172.44.2.246\"\r\ntag_Name = \"EC2_TESTLPRTERRAFORM_EC2_1\"\r\ntags = tomap({\r\n\"AUTEUR\" = \"LPR\"\r\n\"DESCRIPTION\" = \"EC2 CREEE DEPUIS TERRAFORM\"\r\n\"ENVIRONNEMENT\" = \"TEST_TERRAFORM\"\r\n\"Name\" = \"EC2_TESTLPRTERRAFORM_EC2_1\"\r\n})<\/pre>\n<p>A noter que vous pouvez\u00a0 maintenant utiliser la variable <em>${terraform.workspace}<\/em> dans votre code afin de r\u00e9cup\u00e9rer le nom du <em>Workspace <\/em>courant. Pratique pour vos tags (ex: tags = {Name = &#8220;${terraform.workspace}&#8221;<\/p>\n<p>Et comme l&#8217;on ne croit que ce que l&#8217;on voit, on v\u00e9rifie c\u00f4t\u00e9 AWS la cr\u00e9ation de notre EC2:<\/p>\n<p><a href=\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/EC2_1.jpg\" target=\"_blank\" rel=\"noopener\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-9875 size-full\" src=\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/EC2_1.jpg\" alt=\"\" width=\"888\" height=\"603\" srcset=\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/EC2_1.jpg 888w, https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/EC2_1-300x204.jpg 300w, https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/EC2_1-768x522.jpg 768w\" sizes=\"auto, (max-width: 888px) 100vw, 888px\" \/><\/a><\/p>\n<p>On v\u00e9rifie \u00e9alement que le fichier terraform.tfstate soit bien pr\u00e9sent dans notre bucket S3 sous capdata-tfstate\/env:\/<strong>EC2_TESTLPRTERRAFORM_EC2_<span style=\"color: #ff0000;\">1 <\/span><\/strong>(terraform les range par d\u00e9faut par nom de Workspace):<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-9877 size-full\" src=\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/S3_1.jpg\" alt=\"\" width=\"1231\" height=\"459\" srcset=\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/S3_1.jpg 1231w, https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/S3_1-300x112.jpg 300w, https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/S3_1-1024x382.jpg 1024w, https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/S3_1-768x286.jpg 768w\" sizes=\"auto, (max-width: 1231px) 100vw, 1231px\" \/><\/p>\n<p>Maintenant il n&#8217;y-a plus qu&#8217;\u00e0 aller voir votre d\u00e9veloppeur pr\u00e9f\u00e9r\u00e9 et lui signaler que sa machine est pr\u00eate \ud83d\ude09<br \/>\nAh c&#8217;est balo, il vient de se rendre compte que sa demande n&#8217;\u00e9tait pas compl\u00e8te et que finalement il veut bien une deuxi\u00e8me machine pour pouvoir s&#8217;amuser un peu plus!<\/p>\n<p>Heureusement si vous avez suivi, on a pr\u00e9vu le coup:<br \/>\nComme on est fain\u00e9ant on ne touche pas \u00e0 notre code terraform. Et oui sans <em>Workspaces<\/em> certains seraient tent\u00e9s d&#8217;ajouter un autre bloc <em>resource &#8220;aws_instance&#8221; &#8220;mon_ec2_<strong>bis<\/strong>&#8221; {&#8230;}<\/em> dans le <em>main.tf<\/em> ainsi que de nouvelles variables dans le fichier correspondant. Ou alors dupliquer le dossier c:\\temp\\ProjectCreateEC2 en c:\\temp\\ProjectCreateEC2_bis &#8230;<\/p>\n<p>Alors qu&#8217;il suffit de cr\u00e9er un deuxi\u00e8me Workspace et modifier nos variables au passage:<\/p>\n<pre>C:\\temp\\ProjectCreateEC2>terraform workspace new EC2_TESTLPRTERRAFORM_EC2_2\r\n<span style=\"color: #99cc00;\">Created and switched to workspace \"EC2_TESTLPRTERRAFORM_EC2_2\"!<\/span>\r\n\r\n<span style=\"color: #99cc00;\">You're now on a new, empty workspace. Workspaces isolate their state,<\/span>\r\n<span style=\"color: #99cc00;\">so if you run \"terraform plan\" Terraform will not see any existing state<\/span>\r\n<span style=\"color: #99cc00;\">for this configuration.<\/span>\r\n\r\nC:\\temp\\ProjectCreateEC2>terraform workspace list\r\ndefault\r\nEC2_TESTLPRTERRAFORM_EC2_1\r\n* EC2_TESTLPRTERRAFORM_EC2_2<\/pre>\n<p>Et c&#8217;est reparti:<\/p>\n<pre>C:\\temp\\ProjectCreateEC2>terraform apply\r\n\r\nTerraform used the selected providers to generate the following execution plan. Resource actions are indicated with the\r\nfollowing symbols:\r\n+ create\r\n\r\nTerraform will perform the following actions:\r\n\r\n# aws_instance.mon_ec2 will be created\r\n+ resource \"aws_instance\" \"mon_ec2\" {\r\n+ ami = \"ami-09155d2e27d9fb18c\"                                                  <span style=\"color: #ff0000;\"># Vous noterez qu'on a chang\u00e9 entre autre l'AMI source via nos variables<\/span>\r\n+ arn = (known after apply)\r\n+ associate_public_ip_address = (known after apply)\r\n+ availability_zone = (known after apply)\r\n+ cpu_core_count = (known after apply)\r\n[...]\r\n\r\nPlan: 1 to add, 0 to change, 0 to destroy.                                       <span style=\"color: #ff0000;\"># Il s'agit bien d'un ajout et pas d'un to destroy puis to add<\/span>\r\n                                                                                 <span style=\"color: #ff0000;\">comme vu dans la partie II]<\/span>\r\nChanges to Outputs:\r\n<span style=\"color: #99cc00;\">+<\/span> ami = \"ami-09155d2e27d9fb18c\"\r\n<span style=\"color: #99cc00;\">+<\/span> id = (known after apply)\r\n<span style=\"color: #99cc00;\">+<\/span> instance_type = \"t2.micro\"\r\n<span style=\"color: #99cc00;\">+<\/span> private_ip = (known after apply)\r\n<span style=\"color: #99cc00;\">+<\/span> tag_Name = \"EC2_TESTLPRTERRAFORM_EC2_2\"\r\n<span style=\"color: #99cc00;\">+<\/span> tags = {\r\n<span style=\"color: #99cc00;\">+<\/span> \"AUTEUR\" = \"LPR\"\r\n<span style=\"color: #99cc00;\">+<\/span> \"DESCRIPTION\" = \"EC2 CREEE DEPUIS TERRAFORM\"\r\n<span style=\"color: #99cc00;\">+<\/span> \"ENVIRONNEMENT\" = \"TEST_TERRAFORM\"\r\n<span style=\"color: #99cc00;\">+<\/span> \"Name\" = \"EC2_TESTLPRTERRAFORM_EC2_2\"\r\n}\r\n\r\n<strong>Do you want to perform these actions in workspace \"EC2_TESTLPRTERRAFORM_EC2_2\"?<\/strong>  <span style=\"color: #ff0000;\"># Nous sommes bien sur notre deuxi\u00e8me Workspace<\/span>\r\nTerraform will perform the actions described above.\r\nOnly 'yes' will be accepted to approve.\r\n\r\nEnter a value: yes\r\n\r\naws_instance.mon_ec2: Creating...\r\naws_instance.mon_ec2: Still creating... [10s elapsed]\r\naws_instance.mon_ec2: Still creating... [20s elapsed]\r\naws_instance.mon_ec2: Still creating... [30s elapsed]\r\naws_instance.mon_ec2: Creation complete after 32s [id=i-021be48a39c34866e]\r\n\r\n<span style=\"color: #99cc00;\">Apply complete! Resources: 1 added, 0 changed, 0 destroyed.                      <span style=\"color: #ff0000;\"># l'ajout est termin\u00e9 !<\/span><\/span>\r\n\r\n<span style=\"color: #99cc00;\">Outputs:                                                                         <span style=\"color: #ff0000;\"># Affichage des variables de sortie comme vu dans la partie C-<\/span>\u00a0<\/span>\r\n\r\nami = \"ami-09155d2e27d9fb18c\"\r\nid = \"i-021be48a39c34866e\"\r\ninstance_type = \"t2.micro\"\r\nprivate_ip = \"172.44.2.158\"\r\ntag_Name = \"EC2_TESTLPRTERRAFORM_EC2_2\"\r\ntags = tomap({\r\n\"AUTEUR\" = \"LPR\"\r\n\"DESCRIPTION\" = \"EC2 CREEE DEPUIS TERRAFORM\"\r\n\"ENVIRONNEMENT\" = \"TEST_TERRAFORM\"\r\n\"Name\" = \"EC2_TESTLPRTERRAFORM_EC2_2\"\r\n})<\/pre>\n<p>Notre deuxi\u00e8me EC2 est bien l\u00e0 alors que la premi\u00e8re tourne toujours. Ouf on n&#8217;a rien cass\u00e9 aujourd&#8217;hui !<br \/>\n<strong><br \/>\n<\/strong><\/p>\n<p><a href=\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/EC2_2.jpg\" target=\"_blank\" rel=\"noopener\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-9880 size-full\" src=\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/EC2_2.jpg\" alt=\"\" width=\"888\" height=\"602\" srcset=\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/EC2_2.jpg 888w, https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/EC2_2-300x203.jpg 300w, https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/EC2_2-768x521.jpg 768w\" sizes=\"auto, (max-width: 888px) 100vw, 888px\" \/><\/a><\/p>\n<p><strong>Petite apart\u00e9:<\/strong><br \/>\nJ&#8217;en profite pour vous signaler qu&#8217;il existe &#8220;<em>un meta-argument<\/em>&#8221; lifecycle {prevent_destroy = true}\u00a0 \u00e0 ajouter \u00e0 votre ressource terraform si vous souhaitez vous prot\u00e9ger d&#8217;une destruction accidentelle (cf <a href=\"https:\/\/developer.hashicorp.com\/terraform\/language\/meta-arguments\/lifecycle\">The Lifecycle meta-argument<\/a>).<\/p>\n<pre>C:\\temp\\ProjectCreateEC2>terraform plan\r\naws_instance.mon_ec2: Refreshing state... [id=i-021be48a39c34866e]\r\n\u2577\r\n\u2502 <span style=\"color: #ff0000;\">Error:<\/span> Instance cannot be destroyed\r\n\u2502\r\n\u2502 on main.tf line 38:\r\n\u2502 38: <span style=\"text-decoration: underline;\">resource \"aws_instance\" \"mon_ec2\"<\/span> {\r\n\u2502\r\n\u2502 Resource aws_instance.mon_ec2 has lifecycle.prevent_destroy set, but the plan calls for this resource to be\r\n\u2502 destroyed. To avoid this error and continue with the plan, either disable lifecycle.prevent_destroy or reduce the\r\n\u2502 scope of the plan using the -target flag.<\/pre>\n<p>Le deuxi\u00e8me fichier terraform.tfstate est lui aussi bien pr\u00e9sent dans notre bucket S3 sous capdata-tfstate\/env:\/<strong>EC2_TESTLPRTERRAFORM_EC2_<span style=\"color: #ff0000;\">2<\/span><\/strong><\/p>\n<p><a href=\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/S3_2.jpg\" target=\"_blank\" rel=\"noopener\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-9887 size-full\" src=\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/S3_2.jpg\" alt=\"\" width=\"813\" height=\"470\" srcset=\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/S3_2.jpg 813w, https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/S3_2-300x173.jpg 300w, https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/S3_2-768x444.jpg 768w\" sizes=\"auto, (max-width: 813px) 100vw, 813px\" \/><\/a><\/p>\n<p>Je vous invite \u00e0 retourner voir votre d\u00e9veloppeur pr\u00e9f\u00e9r\u00e9 pour lui dire que cette fois vous avez bien fini le job!<br \/>\nMalheureusement en passant devant le bureau de votre deuxi\u00e8me d\u00e9veloppeur pr\u00e9f\u00e9r\u00e9 ce dernier vous fait part de son sentiment de jalousie&#8230;<em>&#8220;Mais heu&#8230; moi aussi je veux bien une machine&#8221;&#8230;<br \/>\n<\/em><\/p>\n<p>Du coup proposez leur de bosser un peu et de d\u00e9velopper une application web qui pourrait par exemple permettre de renseigner vos variables, cr\u00e9er un <em>Workspace<\/em> et lancer votre code Terraform \u00e0 votre place (<em>terraform apply<\/em> ainsi que <em>terraform destroy<\/em> tant qu&#8217;\u00e0 faire).\u00a0 De cette mani\u00e8re ils pourront \u00eatre autonome \u00e0 chaque fois qu&#8217;ils auront besoin d&#8217;un nouvel environnement ;).<\/p>\n<h3><\/h3>\n<h2><span style=\"color: #ff0000;\">VI] Et la table DynamoDB dans tout \u00e7a ??:<\/span><\/h2>\n<p>Effectivement ne me reste plus qu&#8217;\u00e0 vous d\u00e9montrer l&#8217;int\u00e9r\u00eat d&#8217;une table DynamoDB.<br \/>\nJ&#8217;ouvre ici deux invites dos pour simuler un acc\u00e8s concurrentiel \u00e0 notre fichier <em>terraform.tfstate <\/em>correspondant au <em>workspace<\/em> &#8220;EC2_TESTLPRTERRAFORM_EC2_2&#8221;<\/p>\n<h1><a href=\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/State-lock.jpg\" target=\"_blank\" rel=\"noopener\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-9904 size-full\" src=\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/State-lock.jpg\" alt=\"\" width=\"1661\" height=\"800\" srcset=\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/State-lock.jpg 1661w, https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/State-lock-300x144.jpg 300w, https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/State-lock-1024x493.jpg 1024w, https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/State-lock-768x370.jpg 768w, https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/State-lock-1536x740.jpg 1536w\" sizes=\"auto, (max-width: 1661px) 100vw, 1661px\" \/><\/a><\/h1>\n<p>Dans l&#8217;invit de gauche j&#8217;ai modifi\u00e9 l&#8217;AMI source de ma ressource <em>&#8220;aws_instance&#8221; &#8220;mon_ec2&#8221; <\/em>ce qui provoquera naturellement une destruction de l&#8217;EC2 actuelle (<em>1 to destroy<\/em>), pour en cr\u00e9er une autre \u00e0 partir de la nouvelle AMI (<em>1 to add<\/em>). On a vu en introduction que pour faire son <em>apply<\/em> Terraform a besoin de g\u00e9n\u00e9rer un plan et commence donc par consulter son fichier d&#8217;\u00e9tat pour le comparer \u00e0 ce que l&#8217;on souhaite r\u00e9aliser via notre code descriptif. Comme notre <em>remote backend <\/em>est configur\u00e9 pour utiliser une table DynamoDB, il ajoute une ligne dans cette derni\u00e8re pour poser un verrou sur le fichier d&#8217;\u00e9tat en question:<\/p>\n<p><a href=\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/dynamoDBTable.jpg\" target=\"_blank\" rel=\"noopener\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-9907 size-full\" src=\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/dynamoDBTable.jpg\" alt=\"\" width=\"1874\" height=\"1111\" srcset=\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/dynamoDBTable.jpg 1874w, https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/dynamoDBTable-300x178.jpg 300w, https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/dynamoDBTable-1024x607.jpg 1024w, https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/dynamoDBTable-768x455.jpg 768w, https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/dynamoDBTable-1536x911.jpg 1536w\" sizes=\"auto, (max-width: 1874px) 100vw, 1874px\" \/><\/a><\/p>\n<p>Dans l&#8217;invit de droite on constate bien qu&#8217;il est impossible d&#8217;effectuer la moindre action via ce m\u00eame fichier d&#8217;\u00e9tat. M\u00eame un simple terraform plan nous renvoi une erreur. Car en consultant la table DynamoDB Terraform constate qu&#8217;un verrou est d\u00e9j\u00e0 pos\u00e9 sur le fichier <em>capdata-tfstate\/env:\/EC2_TESTLPRTERRAFORM_EC2_2\/terraform.tfstate. <\/em>Il nous donne m\u00eame quelques renseignements suppl\u00e9mentaires concernant notre verrou comme la machine et utilisateur qui l&#8217;ont pos\u00e9, la version de Terraform utilis\u00e9e ainsi que la date.<\/p>\n<p>A noter qu&#8217;il ne faut pas oublier apr\u00e8s un <em>terraform destroy<\/em> de supprimer notre <em>workspace<\/em> correspondant afin de faire du m\u00e9nage au niveau du bucket S3 et de la table DynamoDB:<\/p>\n<pre>C:\\temp\\ProjectCreateEC2>terraform workspace list\r\ndefault\r\nEC2_TESTLPRTERRAFORM_EC2_1\r\n* EC2_TESTLPRTERRAFORM_EC2_2\r\n\r\nC:\\temp\\ProjectCreateEC2>terraform workspace select default\r\n<span style=\"color: #339966;\">Switched to workspace \"default\"<\/span>.\r\n\r\nC:\\temp\\ProjectCreateEC2>terraform workspace list\r\n* default\r\nEC2_TESTLPRTERRAFORM_EC2_1\r\nEC2_TESTLPRTERRAFORM_EC2_2\r\n\r\nC:\\temp\\ProjectCreateEC2>terraform workspace delete EC2_TESTLPRTERRAFORM_EC2_2\r\n<span style=\"color: #339966;\">Deleted workspace \"EC2_TESTLPRTERRAFORM_EC2_2\"!<\/span>\r\n\r\nC:\\temp\\ProjectCreateEC2>terraform workspace list\r\n* default\r\nEC2_TESTLPRTERRAFORM_EC2_1<\/pre>\n<p><a href=\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/dynamoDBTable2.jpg\" target=\"_blank\" rel=\"noopener\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-9908 size-full\" src=\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/dynamoDBTable2.jpg\" alt=\"\" width=\"1567\" height=\"488\" srcset=\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/dynamoDBTable2.jpg 1567w, https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/dynamoDBTable2-300x93.jpg 300w, https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/dynamoDBTable2-1024x319.jpg 1024w, https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/dynamoDBTable2-768x239.jpg 768w, https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/03\/dynamoDBTable2-1536x478.jpg 1536w\" sizes=\"auto, (max-width: 1567px) 100vw, 1567px\" \/><\/a><\/p>\n<h2><span style=\"color: #ff0000;\"><br \/>\nVII] Conclusion:<\/span><\/h2>\n<p>Dans cet article, nous avons pu d\u00e9montrer l&#8217;int\u00e9r\u00eat d&#8217;utiliser les W<em>orkspaces<\/em> dans vos projets Terraform, En effet, il faut les voir comme une possibilit\u00e9 d&#8217;obtenir plusieurs \u00e9tats diff\u00e9rents correspondant \u00e0 diff\u00e9rentes ex\u00e9cutions du m\u00eame code Terraform. A chaque ex\u00e9cution, il suffit alors de modifier les variables afin de distinguer nos ressources dans notre infrastructure. Beaucoup utilisent alors les <em>Workspaces <\/em>dans le but de dupliquer des environnements production \/ d\u00e9veloppement \/ qualification par exemple. Cela \u00e9vite d&#8217;avoir \u00e0 maintenir plusieurs projets Terraform diff\u00e9rents (un par environnement).<\/p>\n<p>Ici il s&#8217;agissait par exemple d&#8217;offrir la possibilit\u00e9 \u00e0 vos utilisateurs d&#8217;instancier leur propre EC2 sur un VPC pr\u00e9-provisionn\u00e9 c\u00f4t\u00e9 AWS, de mani\u00e8re compl\u00e8tement automatis\u00e9 sans avoir \u00e0 modifier de code Terraform <span style=\"text-decoration: underline;\">\u00e0 chaque fois<\/span>; et de <span style=\"text-decoration: underline;\">mani\u00e8re native<\/span> c&#8217;est-\u00e0-dire sans utiliser <span style=\"text-decoration: underline;\">aucun autre outils<\/span>. A part \u00e9ventuellement la mise en place d&#8217;une interface utilisateur type page Web.<\/p>\n<p>Nous comparerons certainement l&#8217;utilisation des <em>Workspaces <\/em>de<em> Terraform<\/em> \u00e0 l&#8217;utilisation de l&#8217;outil tier <em>Terragrunt (<\/em>qui je le rappel est une &#8220;surcouche&#8221; \u00e0 <em>Terraform<\/em> permettant entre autre d&#8217;\u00e9viter la d\u00e9duplication de code<em>)<\/em> dans un prochain article&#8230;<\/p>\n<a class=\"synved-social-button synved-social-button-share synved-social-size-24 synved-social-resolution-single synved-social-provider-twitter nolightbox\" data-provider=\"twitter\" target=\"_blank\" rel=\"nofollow\" title=\"Share on Twitter\" href=\"https:\/\/twitter.com\/intent\/tweet?url=https%3A%2F%2Fblog.capdata.fr%2Findex.php%2Fwp-json%2Fwp%2Fv2%2Fposts%2F9738&#038;text=Article%20sur%20le%20blog%20de%20la%20Capdata%20Tech%20Team%20%3A%20\" style=\"font-size: 0px;width:24px;height:24px;margin:0;margin-bottom:5px;margin-right:5px\"><img loading=\"lazy\" decoding=\"async\" alt=\"twitter\" title=\"Share on Twitter\" class=\"synved-share-image synved-social-image synved-social-image-share\" width=\"24\" height=\"24\" style=\"display: inline;width:24px;height:24px;margin: 0;padding: 0;border: none;box-shadow: none\" src=\"https:\/\/blog.capdata.fr\/wp-content\/plugins\/social-media-feather\/synved-social\/image\/social\/regular\/48x48\/twitter.png\" \/><\/a><a class=\"synved-social-button synved-social-button-share synved-social-size-24 synved-social-resolution-single synved-social-provider-linkedin nolightbox\" data-provider=\"linkedin\" target=\"_blank\" rel=\"nofollow\" title=\"Share on Linkedin\" href=\"https:\/\/www.linkedin.com\/shareArticle?mini=true&#038;url=https%3A%2F%2Fblog.capdata.fr%2Findex.php%2Fwp-json%2Fwp%2Fv2%2Fposts%2F9738&#038;title=Workspaces%20Terraform%20avec%20AWS%20S3%20et%20DynamoDB\" style=\"font-size: 0px;width:24px;height:24px;margin:0;margin-bottom:5px;margin-right:5px\"><img loading=\"lazy\" decoding=\"async\" alt=\"linkedin\" title=\"Share on Linkedin\" class=\"synved-share-image synved-social-image synved-social-image-share\" width=\"24\" height=\"24\" style=\"display: inline;width:24px;height:24px;margin: 0;padding: 0;border: none;box-shadow: none\" src=\"https:\/\/blog.capdata.fr\/wp-content\/plugins\/social-media-feather\/synved-social\/image\/social\/regular\/48x48\/linkedin.png\" \/><\/a><a class=\"synved-social-button synved-social-button-share synved-social-size-24 synved-social-resolution-single synved-social-provider-mail nolightbox\" data-provider=\"mail\" rel=\"nofollow\" title=\"Share by email\" href=\"mailto:?subject=Workspaces%20Terraform%20avec%20AWS%20S3%20et%20DynamoDB&#038;body=Article%20sur%20le%20blog%20de%20la%20Capdata%20Tech%20Team%20%3A%20:%20https%3A%2F%2Fblog.capdata.fr%2Findex.php%2Fwp-json%2Fwp%2Fv2%2Fposts%2F9738\" style=\"font-size: 0px;width:24px;height:24px;margin:0;margin-bottom:5px\"><img loading=\"lazy\" decoding=\"async\" alt=\"mail\" title=\"Share by email\" class=\"synved-share-image synved-social-image synved-social-image-share\" width=\"24\" height=\"24\" style=\"display: inline;width:24px;height:24px;margin: 0;padding: 0;border: none;box-shadow: none\" src=\"https:\/\/blog.capdata.fr\/wp-content\/plugins\/social-media-feather\/synved-social\/image\/social\/regular\/48x48\/mail.png\" \/><\/a>","protected":false},"excerpt":{"rendered":"<p>I] Introduction: Terraform est une application dite &#8220;stateful&#8221;. C&#8217;est-\u00e0-dire que toutes les modifications apport\u00e9es \u00e0 votre infrastructure via cet outil sont stock\u00e9es dans un fichier State (\u00e9tat) au format json nomm\u00e9 terraform.tfstate. Ce fichier est cr\u00e9\u00e9 lors de la premi\u00e8re&hellip; <a href=\"https:\/\/blog.capdata.fr\/index.php\/workspaces-terraform-avec-aws-s3-et-dynamodb\/\" class=\"more-link\">Continuer la lecture <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":23,"featured_media":10021,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[295,442],"tags":[446,416,445],"class_list":["post-9738","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-aws","category-devops","tag-dynamodb","tag-s3","tag-terraform"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v20.8 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Workspaces Terraform avec AWS S3 et DynamoDB - Capdata TECH BLOG<\/title>\n<meta name=\"description\" content=\"Comment utiliser les workspaces Terraform avec des buckets AWS S3 et une table AWS DynamoDB\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/blog.capdata.fr\/index.php\/workspaces-terraform-avec-aws-s3-et-dynamodb\/\" \/>\n<meta property=\"og:locale\" content=\"fr_FR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Workspaces Terraform avec AWS S3 et DynamoDB - Capdata TECH BLOG\" \/>\n<meta property=\"og:description\" content=\"Comment utiliser les workspaces Terraform avec des buckets AWS S3 et une table AWS DynamoDB\" \/>\n<meta property=\"og:url\" content=\"https:\/\/blog.capdata.fr\/index.php\/workspaces-terraform-avec-aws-s3-et-dynamodb\/\" \/>\n<meta property=\"og:site_name\" content=\"Capdata TECH BLOG\" \/>\n<meta property=\"article:published_time\" content=\"2023-04-12T14:30:11+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/04\/Image.png\" \/>\n\t<meta property=\"og:image:width\" content=\"713\" \/>\n\t<meta property=\"og:image:height\" content=\"530\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Louis PROU\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"\u00c9crit par\" \/>\n\t<meta name=\"twitter:data1\" content=\"Louis PROU\" \/>\n\t<meta name=\"twitter:label2\" content=\"Dur\u00e9e de lecture estim\u00e9e\" \/>\n\t<meta name=\"twitter:data2\" content=\"23 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/blog.capdata.fr\/index.php\/workspaces-terraform-avec-aws-s3-et-dynamodb\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/blog.capdata.fr\/index.php\/workspaces-terraform-avec-aws-s3-et-dynamodb\/\"},\"author\":{\"name\":\"Louis PROU\",\"@id\":\"https:\/\/blog.capdata.fr\/#\/schema\/person\/a4848b0c7faa6956f1a1520d6cc34ae9\"},\"headline\":\"Workspaces Terraform avec AWS S3 et DynamoDB\",\"datePublished\":\"2023-04-12T14:30:11+00:00\",\"dateModified\":\"2023-04-12T14:30:11+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/blog.capdata.fr\/index.php\/workspaces-terraform-avec-aws-s3-et-dynamodb\/\"},\"wordCount\":3463,\"commentCount\":1,\"publisher\":{\"@id\":\"https:\/\/blog.capdata.fr\/#organization\"},\"keywords\":[\"DynamoDB\",\"S3\",\"terraform\"],\"articleSection\":[\"AWS\",\"Devops\"],\"inLanguage\":\"fr-FR\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/blog.capdata.fr\/index.php\/workspaces-terraform-avec-aws-s3-et-dynamodb\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/blog.capdata.fr\/index.php\/workspaces-terraform-avec-aws-s3-et-dynamodb\/\",\"url\":\"https:\/\/blog.capdata.fr\/index.php\/workspaces-terraform-avec-aws-s3-et-dynamodb\/\",\"name\":\"Workspaces Terraform avec AWS S3 et DynamoDB - Capdata TECH BLOG\",\"isPartOf\":{\"@id\":\"https:\/\/blog.capdata.fr\/#website\"},\"datePublished\":\"2023-04-12T14:30:11+00:00\",\"dateModified\":\"2023-04-12T14:30:11+00:00\",\"description\":\"Comment utiliser les workspaces Terraform avec des buckets AWS S3 et une table AWS DynamoDB\",\"breadcrumb\":{\"@id\":\"https:\/\/blog.capdata.fr\/index.php\/workspaces-terraform-avec-aws-s3-et-dynamodb\/#breadcrumb\"},\"inLanguage\":\"fr-FR\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/blog.capdata.fr\/index.php\/workspaces-terraform-avec-aws-s3-et-dynamodb\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/blog.capdata.fr\/index.php\/workspaces-terraform-avec-aws-s3-et-dynamodb\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Accueil\",\"item\":\"https:\/\/blog.capdata.fr\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Workspaces Terraform avec AWS S3 et DynamoDB\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/blog.capdata.fr\/#website\",\"url\":\"https:\/\/blog.capdata.fr\/\",\"name\":\"Capdata TECH BLOG\",\"description\":\"Le blog technique sur les bases de donn\u00e9es de CAP DATA Consulting\",\"publisher\":{\"@id\":\"https:\/\/blog.capdata.fr\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/blog.capdata.fr\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"fr-FR\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/blog.capdata.fr\/#organization\",\"name\":\"Capdata TECH BLOG\",\"url\":\"https:\/\/blog.capdata.fr\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"fr-FR\",\"@id\":\"https:\/\/blog.capdata.fr\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/01\/logo_capdata.webp\",\"contentUrl\":\"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/01\/logo_capdata.webp\",\"width\":800,\"height\":254,\"caption\":\"Capdata TECH BLOG\"},\"image\":{\"@id\":\"https:\/\/blog.capdata.fr\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.linkedin.com\/company\/cap-data-consulting\/mycompany\/\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/blog.capdata.fr\/#\/schema\/person\/a4848b0c7faa6956f1a1520d6cc34ae9\",\"name\":\"Louis PROU\",\"url\":\"https:\/\/blog.capdata.fr\/index.php\/author\/lprou\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Workspaces Terraform avec AWS S3 et DynamoDB - Capdata TECH BLOG","description":"Comment utiliser les workspaces Terraform avec des buckets AWS S3 et une table AWS DynamoDB","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/blog.capdata.fr\/index.php\/workspaces-terraform-avec-aws-s3-et-dynamodb\/","og_locale":"fr_FR","og_type":"article","og_title":"Workspaces Terraform avec AWS S3 et DynamoDB - Capdata TECH BLOG","og_description":"Comment utiliser les workspaces Terraform avec des buckets AWS S3 et une table AWS DynamoDB","og_url":"https:\/\/blog.capdata.fr\/index.php\/workspaces-terraform-avec-aws-s3-et-dynamodb\/","og_site_name":"Capdata TECH BLOG","article_published_time":"2023-04-12T14:30:11+00:00","og_image":[{"width":713,"height":530,"url":"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/04\/Image.png","type":"image\/png"}],"author":"Louis PROU","twitter_card":"summary_large_image","twitter_misc":{"\u00c9crit par":"Louis PROU","Dur\u00e9e de lecture estim\u00e9e":"23 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/blog.capdata.fr\/index.php\/workspaces-terraform-avec-aws-s3-et-dynamodb\/#article","isPartOf":{"@id":"https:\/\/blog.capdata.fr\/index.php\/workspaces-terraform-avec-aws-s3-et-dynamodb\/"},"author":{"name":"Louis PROU","@id":"https:\/\/blog.capdata.fr\/#\/schema\/person\/a4848b0c7faa6956f1a1520d6cc34ae9"},"headline":"Workspaces Terraform avec AWS S3 et DynamoDB","datePublished":"2023-04-12T14:30:11+00:00","dateModified":"2023-04-12T14:30:11+00:00","mainEntityOfPage":{"@id":"https:\/\/blog.capdata.fr\/index.php\/workspaces-terraform-avec-aws-s3-et-dynamodb\/"},"wordCount":3463,"commentCount":1,"publisher":{"@id":"https:\/\/blog.capdata.fr\/#organization"},"keywords":["DynamoDB","S3","terraform"],"articleSection":["AWS","Devops"],"inLanguage":"fr-FR","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/blog.capdata.fr\/index.php\/workspaces-terraform-avec-aws-s3-et-dynamodb\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/blog.capdata.fr\/index.php\/workspaces-terraform-avec-aws-s3-et-dynamodb\/","url":"https:\/\/blog.capdata.fr\/index.php\/workspaces-terraform-avec-aws-s3-et-dynamodb\/","name":"Workspaces Terraform avec AWS S3 et DynamoDB - Capdata TECH BLOG","isPartOf":{"@id":"https:\/\/blog.capdata.fr\/#website"},"datePublished":"2023-04-12T14:30:11+00:00","dateModified":"2023-04-12T14:30:11+00:00","description":"Comment utiliser les workspaces Terraform avec des buckets AWS S3 et une table AWS DynamoDB","breadcrumb":{"@id":"https:\/\/blog.capdata.fr\/index.php\/workspaces-terraform-avec-aws-s3-et-dynamodb\/#breadcrumb"},"inLanguage":"fr-FR","potentialAction":[{"@type":"ReadAction","target":["https:\/\/blog.capdata.fr\/index.php\/workspaces-terraform-avec-aws-s3-et-dynamodb\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/blog.capdata.fr\/index.php\/workspaces-terraform-avec-aws-s3-et-dynamodb\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Accueil","item":"https:\/\/blog.capdata.fr\/"},{"@type":"ListItem","position":2,"name":"Workspaces Terraform avec AWS S3 et DynamoDB"}]},{"@type":"WebSite","@id":"https:\/\/blog.capdata.fr\/#website","url":"https:\/\/blog.capdata.fr\/","name":"Capdata TECH BLOG","description":"Le blog technique sur les bases de donn\u00e9es de CAP DATA Consulting","publisher":{"@id":"https:\/\/blog.capdata.fr\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/blog.capdata.fr\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"fr-FR"},{"@type":"Organization","@id":"https:\/\/blog.capdata.fr\/#organization","name":"Capdata TECH BLOG","url":"https:\/\/blog.capdata.fr\/","logo":{"@type":"ImageObject","inLanguage":"fr-FR","@id":"https:\/\/blog.capdata.fr\/#\/schema\/logo\/image\/","url":"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/01\/logo_capdata.webp","contentUrl":"https:\/\/blog.capdata.fr\/wp-content\/uploads\/2023\/01\/logo_capdata.webp","width":800,"height":254,"caption":"Capdata TECH BLOG"},"image":{"@id":"https:\/\/blog.capdata.fr\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.linkedin.com\/company\/cap-data-consulting\/mycompany\/"]},{"@type":"Person","@id":"https:\/\/blog.capdata.fr\/#\/schema\/person\/a4848b0c7faa6956f1a1520d6cc34ae9","name":"Louis PROU","url":"https:\/\/blog.capdata.fr\/index.php\/author\/lprou\/"}]}},"_links":{"self":[{"href":"https:\/\/blog.capdata.fr\/index.php\/wp-json\/wp\/v2\/posts\/9738","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.capdata.fr\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.capdata.fr\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.capdata.fr\/index.php\/wp-json\/wp\/v2\/users\/23"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.capdata.fr\/index.php\/wp-json\/wp\/v2\/comments?post=9738"}],"version-history":[{"count":169,"href":"https:\/\/blog.capdata.fr\/index.php\/wp-json\/wp\/v2\/posts\/9738\/revisions"}],"predecessor-version":[{"id":10043,"href":"https:\/\/blog.capdata.fr\/index.php\/wp-json\/wp\/v2\/posts\/9738\/revisions\/10043"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.capdata.fr\/index.php\/wp-json\/wp\/v2\/media\/10021"}],"wp:attachment":[{"href":"https:\/\/blog.capdata.fr\/index.php\/wp-json\/wp\/v2\/media?parent=9738"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.capdata.fr\/index.php\/wp-json\/wp\/v2\/categories?post=9738"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.capdata.fr\/index.php\/wp-json\/wp\/v2\/tags?post=9738"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}