{"id":1779,"date":"2022-01-26T10:08:51","date_gmt":"2022-01-26T08:08:51","guid":{"rendered":"https:\/\/www.netexpertise.eu\/en\/?p=1779"},"modified":"2022-01-26T10:09:11","modified_gmt":"2022-01-26T08:09:11","slug":"terraform-shared-resources-ssh-keys-case-study","status":"publish","type":"post","link":"http:\/\/www.netexpertise.eu\/en\/devops\/terraform\/terraform-shared-resources-ssh-keys-case-study.html","title":{"rendered":"Terraform Shared Resources: SSH Keys Case Study"},"content":{"rendered":"\n<p>Terraform lets you automate infrastructure creation and change in the cloud, what is commonly called infrastructure as code. I need to create a virtual machine, which must embed 3 SSH keys that belong to administrators. I want this Terraform shared resource to be reusable by other modules. This example on <a href=\"\/en\/tag\/ibmcloud\">IBM Cloud<\/a> is based on the IBM plugin for Terraform but this method remains valid for other cloud providers indeed.<br>I did not include the VPC creation, neither subnets and security groups to make it more readable.<br><br><\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img decoding=\"async\" src=\"\/uploads\/icon-clipart-recycle-recover-reuse-3418168-e1642486455484.png\" alt=\"Reuse Terraform Shared Resources\"\/><\/figure><\/div>\n\n\n\n<h2 class=\"wp-block-heading\"><br>Resources in a Single Module<\/h2>\n\n\n\n<p>We&#8217;ll start with 2 files: ssh.tf containing the code that creates administrator SSH keys, and vm.tf in the same directory, that creates the server. Keys are then given to the VM as input settings.<br><br><\/p>\n\n\n\n<pre title=\"ssh.tf\" class=\"wp-block-code\"><code lang=\"vim\" class=\"language-vim\">resource \"ibm_is_ssh_key\" \"user1_sshkey\" {\n  name       = \"user1\"\n  public_key = \"ssh-rsa AAAAB3[...]k+XR==\"\n}\n\nresource \"ibm_is_ssh_key\" \"user2_sshkey\" {\n  name       = \"user2\"\n  public_key = \"ssh-rsa AAAAB3[...]Zo9R==\"\n}\n\nresource \"ibm_is_ssh_key\" \"user3_sshkey\" {\n  name       = \"user3\"\n  public_key = \"ssh-rsa AAAAB3[...]67GqV=\"\n}<\/code><\/pre>\n\n\n\n<pre title=\"vm.tf\" class=\"wp-block-code\"><code lang=\"vim\" class=\"language-vim\">resource \"ibm_is_instance\" \"server1\" {\n  name    = \"server1\"\n  image   = var.image\n  profile = var.profile\n  vpc  = ibm_is_vpc.vpc.id\n  zone = var.zone1\n\n  primary_network_interface {\n    subnet          = ibm_is_subnet.subnet1.id\n    security_groups = [ibm_is_vpc.vpc.default_security_group]\n  }\n\n  keys = [\n    ibm_is_ssh_key.user1_sshkey.id,\n    ibm_is_ssh_key.user2_sshkey.id,\n    ibm_is_ssh_key.user3_sshkey.id\n  ]\n}<\/code><\/pre>\n\n\n\n<p><br>The code is pretty simple but raises a major problem:<br>SSH keys are not reusable in another Terraform module. If we copy\/paste that piece of code to create a second VM, an error will throw keys already exist. Also, adding a new key requires to modify the 2 Terraform files.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><br>Terraform Shared Resources<\/h2>\n\n\n\n<p>As a consequence, we need to create SSH keys in a brand new independent Terraform module and make them available to other modules. We can achieve this exporting key ids with output values. Outputs make it possible to expose variables to the command line or other Terraform modules.<br>Let&#8217;s move the key declaration to a new Terraform directory to which we&#8217;ll add an output <em>ssh_keys<\/em> that sends back an array with their respective ids, knowing this is what VMs expect as input.<\/p>\n\n\n\n<pre title=\"ssh.tf\" class=\"wp-block-code\"><code lang=\"vim\" class=\"language-vim\">resource \"ibm_is_ssh_key\" \"user1_sshkey\" {\n  name       = \"user1\"\n  public_key = \"ssh-rsa AAAAB3[...]k+XR==\"\n}\n\nresource \"ibm_is_ssh_key\" \"user2_sshkey\" {\n  name       = \"user2\"\n  public_key = \"ssh-rsa AAAAB3[...]Zo9R==\"\n}\n\nresource \"ibm_is_ssh_key\" \"user3_sshkey\" {\n  name       = \"user3\"\n  public_key = \"ssh-rsa AAAAB3[...]67GqV=\"\n}\n\noutput \"ssh_keys\" {\n  value = [\n    ibm_is_ssh_key.user1_sshkey.id,\n    ibm_is_ssh_key.user2_sshkey.id,\n    ibm_is_ssh_key.user3_sshkey.id\n  ]\n}<\/code><\/pre>\n\n\n\n<p><br>Once you launch <em>terraform apply<\/em>, you can display <a href=\"https:\/\/www.terraform.io\/language\/values\/outputs\" target=\"_blank\" rel=\"noreferrer noopener\">output<\/a> values with <em>terraform output<\/em>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"bash\" class=\"language-bash\">$ terraform output\nssh_keys = [\n  \"r010-3e98b94b-9518-4e11-9ac4-a014120344dc\",\n  \"r010-b271dce5-4744-48c3-9001-a620e99563d9\",\n  \"r010-9358c6ab-0eed-4de7-a4a0-4ba20b2c04c9\",\n]<\/code><\/pre>\n\n\n\n<p><br>This is exactly what we need. All is left to do is get this output through a data lookup and process it in the VM module.<\/p>\n\n\n\n<pre title=\"vm.tf\" class=\"wp-block-code\"><code lang=\"vim\" class=\"language-vim\">data \"terraform_remote_state\" \"ssh_keys\" {\n  backend = \"local\"\n  config = {\n    path = \"..\/ssh_keys\/terraform.tfstate\"\n  }\n}\n\nresource \"ibm_is_instance\" \"server1\" {\n  name    = \"server1\"\n  image   = var.image\n  profile = var.profile\n\n  primary_network_interface {\n    subnet          = ibm_is_subnet.subnet1.id\n    security_groups = [ibm_is_vpc.vpc.default_security_group]\n  }\n\n  vpc  = ibm_is_vpc.vpc.id\n  zone = var.zone1\n  keys = data.terraform_remote_state.ssh_keys.outputs.ssh_keys\n}<\/code><\/pre>\n\n\n\n<p><br>That&#8217;s better, we are able to handle SSH keys independently of other Terraform modules and reuse them at will. The data lookup path is the relative path to the directory that contains the ssh.tf file.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><br>Variables in Key\/Value Maps<\/h2>\n\n\n\n<p>That&#8217;s better but we could make shared resources (SSH keys in this case) creation more elegant.<br>Indeed, adding a new key has to be done in 2 different places: create a Terraform resource, and add it to the values returned in the output. Which is tedious and error-prone.<br>Moreover, it is quite difficult to read, it would be better to separate code and values.<\/p>\n\n\n\n<p>To do this, we are going to store the keys in a <a href=\"https:\/\/www.terraform.io\/language\/expressions\/types#map\" target=\"_blank\" rel=\"noreferrer noopener\">map<\/a> (an array) in a file terraform.tfvars, that is loaded automatically. A file called terraform.tfvars, loads automatically in Terraform. Name it anything else .tfvars<\/p>\n\n\n\n<pre title=\"terraform.tfvars\" class=\"wp-block-code\"><code lang=\"vim\" class=\"language-vim\">ssh_keys = {\n  \"user1\" = \"ssh-rsa AAAAB3[...]k+XR==\"\n  \"user2\" = \"ssh-rsa AAAAB3[...]Zo9R==\"\n  \"user3\" = \"ssh-rsa AAAAB3[...]67GqV=\"\n}<\/code><\/pre>\n\n\n\n<p><br>In ssh.tf, we&#8217;ll loop on that key\/value array to create resources, and export them as outputs.<\/p>\n\n\n\n<pre title=\"ssh.tf\" class=\"wp-block-code\"><code lang=\"vim\" class=\"language-vim\"># Array definition\nvariable \"ssh_keys\" {\n  type = map(string)\n}\n\nresource \"ibm_is_ssh_key\" \"keys\" {\n  for_each = var.ssh_keys\n  name = each.key\n  public_key = each.value\n}\n\noutput \"ssh_keys\" {\n  value = values(ibm_is_ssh_key.keys)[*].id\n}<\/code><\/pre>\n\n\n\n<p><br>Getting values is a bit tricky. I started to display an output values(ibm_is_ssh_key.keys) to analyse the structure and get ids I needed.<\/p>\n\n\n\n<p>In the end, a new shared resource (an SSH key in this case) can be created with a simple insert in a map, witthin a file that only contains variables. In one single place. Anybody can take care of it without reading or understanding the code.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Terraform lets you automate infrastructure creation and change in the cloud, what is commonly called infrastructure as code. I need to create a virtual machine, which must embed 3 SSH keys that belong to administrators. I want this Terraform shared resource to be reusable by other modules. This example on IBM Cloud is based on [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0},"categories":[425,452],"tags":[436,453],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v21.8.1 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Netexpertise - Terraform Shared Resources: SSH Keys Case Study<\/title>\n<meta name=\"description\" content=\"Create Terraform shared resources and access them from other modules with output values. Example of a VM reaching out SSH keys.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.netexpertise.eu\/en\/devops\/terraform\/terraform-shared-resources-ssh-keys-case-study.html\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Netexpertise - Terraform Shared Resources: SSH Keys Case Study\" \/>\n<meta property=\"og:description\" content=\"Create Terraform shared resources and access them from other modules with output values. Example of a VM reaching out SSH keys.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.netexpertise.eu\/en\/devops\/terraform\/terraform-shared-resources-ssh-keys-case-study.html\" \/>\n<meta property=\"og:site_name\" content=\"Netexpertise\" \/>\n<meta property=\"article:published_time\" content=\"2022-01-26T08:08:51+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2022-01-26T08:09:11+00:00\" \/>\n<meta name=\"author\" content=\"dave\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@netexpertise\" \/>\n<meta name=\"twitter:site\" content=\"@netexpertise\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.netexpertise.eu\/en\/devops\/terraform\/terraform-shared-resources-ssh-keys-case-study.html\",\"url\":\"https:\/\/www.netexpertise.eu\/en\/devops\/terraform\/terraform-shared-resources-ssh-keys-case-study.html\",\"name\":\"Netexpertise - Terraform Shared Resources: SSH Keys Case Study\",\"isPartOf\":{\"@id\":\"https:\/\/www.netexpertise.eu\/en\/#website\"},\"datePublished\":\"2022-01-26T08:08:51+00:00\",\"dateModified\":\"2022-01-26T08:09:11+00:00\",\"author\":{\"@id\":\"https:\/\/www.netexpertise.eu\/en\/#\/schema\/person\/cb4cd666549d22e9070ec1cfc1a496fa\"},\"description\":\"Create Terraform shared resources and access them from other modules with output values. Example of a VM reaching out SSH keys.\",\"breadcrumb\":{\"@id\":\"https:\/\/www.netexpertise.eu\/en\/devops\/terraform\/terraform-shared-resources-ssh-keys-case-study.html#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.netexpertise.eu\/en\/devops\/terraform\/terraform-shared-resources-ssh-keys-case-study.html\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.netexpertise.eu\/en\/devops\/terraform\/terraform-shared-resources-ssh-keys-case-study.html#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.netexpertise.eu\/en\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Terraform Shared Resources: SSH Keys Case Study\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.netexpertise.eu\/en\/#website\",\"url\":\"https:\/\/www.netexpertise.eu\/en\/\",\"name\":\"Netexpertise\",\"description\":\"Systems \/ Networks \/ DevOps\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.netexpertise.eu\/en\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.netexpertise.eu\/en\/#\/schema\/person\/cb4cd666549d22e9070ec1cfc1a496fa\",\"name\":\"dave\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.netexpertise.eu\/en\/#\/schema\/person\/image\/\",\"url\":\"http:\/\/1.gravatar.com\/avatar\/1129916e1f4955bd632f27f836f64e55?s=96&d=mm&r=g\",\"contentUrl\":\"http:\/\/1.gravatar.com\/avatar\/1129916e1f4955bd632f27f836f64e55?s=96&d=mm&r=g\",\"caption\":\"dave\"},\"sameAs\":[\"http:\/\/www.netexpertise.eu\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Netexpertise - Terraform Shared Resources: SSH Keys Case Study","description":"Create Terraform shared resources and access them from other modules with output values. Example of a VM reaching out SSH keys.","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:\/\/www.netexpertise.eu\/en\/devops\/terraform\/terraform-shared-resources-ssh-keys-case-study.html","og_locale":"en_US","og_type":"article","og_title":"Netexpertise - Terraform Shared Resources: SSH Keys Case Study","og_description":"Create Terraform shared resources and access them from other modules with output values. Example of a VM reaching out SSH keys.","og_url":"https:\/\/www.netexpertise.eu\/en\/devops\/terraform\/terraform-shared-resources-ssh-keys-case-study.html","og_site_name":"Netexpertise","article_published_time":"2022-01-26T08:08:51+00:00","article_modified_time":"2022-01-26T08:09:11+00:00","author":"dave","twitter_card":"summary_large_image","twitter_creator":"@netexpertise","twitter_site":"@netexpertise","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/www.netexpertise.eu\/en\/devops\/terraform\/terraform-shared-resources-ssh-keys-case-study.html","url":"https:\/\/www.netexpertise.eu\/en\/devops\/terraform\/terraform-shared-resources-ssh-keys-case-study.html","name":"Netexpertise - Terraform Shared Resources: SSH Keys Case Study","isPartOf":{"@id":"https:\/\/www.netexpertise.eu\/en\/#website"},"datePublished":"2022-01-26T08:08:51+00:00","dateModified":"2022-01-26T08:09:11+00:00","author":{"@id":"https:\/\/www.netexpertise.eu\/en\/#\/schema\/person\/cb4cd666549d22e9070ec1cfc1a496fa"},"description":"Create Terraform shared resources and access them from other modules with output values. Example of a VM reaching out SSH keys.","breadcrumb":{"@id":"https:\/\/www.netexpertise.eu\/en\/devops\/terraform\/terraform-shared-resources-ssh-keys-case-study.html#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.netexpertise.eu\/en\/devops\/terraform\/terraform-shared-resources-ssh-keys-case-study.html"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.netexpertise.eu\/en\/devops\/terraform\/terraform-shared-resources-ssh-keys-case-study.html#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.netexpertise.eu\/en"},{"@type":"ListItem","position":2,"name":"Terraform Shared Resources: SSH Keys Case Study"}]},{"@type":"WebSite","@id":"https:\/\/www.netexpertise.eu\/en\/#website","url":"https:\/\/www.netexpertise.eu\/en\/","name":"Netexpertise","description":"Systems \/ Networks \/ DevOps","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.netexpertise.eu\/en\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.netexpertise.eu\/en\/#\/schema\/person\/cb4cd666549d22e9070ec1cfc1a496fa","name":"dave","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.netexpertise.eu\/en\/#\/schema\/person\/image\/","url":"http:\/\/1.gravatar.com\/avatar\/1129916e1f4955bd632f27f836f64e55?s=96&d=mm&r=g","contentUrl":"http:\/\/1.gravatar.com\/avatar\/1129916e1f4955bd632f27f836f64e55?s=96&d=mm&r=g","caption":"dave"},"sameAs":["http:\/\/www.netexpertise.eu"]}]}},"_links":{"self":[{"href":"http:\/\/www.netexpertise.eu\/en\/wp-json\/wp\/v2\/posts\/1779"}],"collection":[{"href":"http:\/\/www.netexpertise.eu\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.netexpertise.eu\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.netexpertise.eu\/en\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/www.netexpertise.eu\/en\/wp-json\/wp\/v2\/comments?post=1779"}],"version-history":[{"count":0,"href":"http:\/\/www.netexpertise.eu\/en\/wp-json\/wp\/v2\/posts\/1779\/revisions"}],"wp:attachment":[{"href":"http:\/\/www.netexpertise.eu\/en\/wp-json\/wp\/v2\/media?parent=1779"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.netexpertise.eu\/en\/wp-json\/wp\/v2\/categories?post=1779"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.netexpertise.eu\/en\/wp-json\/wp\/v2\/tags?post=1779"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}