Managing the Same AWS Key Pair in Multiple Terraform Workspaces
June 1, 2020
AWS key pairs allow you to put your SSH key on EC2 instances when the are created, allowing you to SSH into an instance with a public key instead of a password. If you have multiple Terraform workspaces, eg. staging and production, using the same key pair in multiple workspaces can cause some problems.
The Problem
Consider the following Terraform block in the staging workspace:
If you want to use the same key pair in the production workspace, you might switch workspaces and import the key pair:
This will import the key pair, but there is a problem—running terraform plan in the production workspace shows that the key pair will be recreated:
Notice the "forces replacement" next to the public_key. Running terraform import imported the key pair but not the public_key for the key pair—this is because the AWS API does not expose the public key.
We can confirm that the Terraform state does not have the public key by running terraform state show:
The Solution
We’re going to update terraform.tfstate to include public key. I do not recommend this approach if you’re using Terraform as a team, as editing the Terraform state file by hand can lead to unexpected behaviors if a change to the infrastructure is made while you’re doing this.
Make a note of the public_key from above, and then switch to the production workspace:
Edit Terraform state file
The next step is to get the Terraform state file. Your mileage may vary depending on which Terraform backend you're using. In my case, I use the S3 backend, so I need to copy the production state file so I can edit it:
Find the resource with type aws_key_pair named key_pair. Add the public key from above to the public_key attribute:
Finally, we need to re-upload the state file:
To ensure the public key was added to the key pair state, we can run terraform plan to verify that a second key pair won’t be created:
Conclusion
That's it! Even though importing the AWS key pair didn't import the public key, we can manipulate the Terraform state to include the public key so that the resource is not recreated.
While I went with the above solution for my use case, there are other solutions to this problem:
set up each Terraform workspace to use different AWS accounts
use different key pairs for each workspace, naming them like ryan-staging and ryan-production