Organizing Terraform Configuration Files & Deployment
You may be wondering, how to deploy cloud infrastructure in Terraform without providing your credentials in the configuration files.
Explanation: From a local machine, when you run the “aws configure” command, the values entered for ACCESS KEY ID and SECRET ACCESS KEY_ID are located in the ~/.aws/credentials log file. This folder is not a directory and can not be accessed as such.
Let’s go through the steps to get your AWS credentials on your local machine (FYI: Terraform Cloud [remote backed] allows you to store your credentials securely in Terraform Cloud)
Local:
The above steps will store your credentials in the ~/.aws/credentials log file (assuming the aws cli is installed for your operating system). Enter the proper region & output format you prefer (if the region and output formats are valid do not enter any values, click enter and continue).
Login into the terraform console and navigate to the workspaces tab, select variables under your desired workspace and scroll down to Environment Variables, and add your access key id and secret access key id (shown below).
Now that our credentials are stored let’s move on to organizing your terraform files and code. Before starting this step, I want to convey that there are easier ways to deploy infrastructure using modules. I will briefly speak on the modules before ending this lab.
Organizing your configuration files
It is recommended best practice to separate your configuration files (i.e. resources, provider, modules, variables..etc) to ensure that your code stays short, readable, and as clean looking as possible.
There are no provider’s credentials in the “my ec2.tf” configuration file. The provider reference resides in a different config file, and the variables as well. Maintaining a clean configuration that will be easy to read for any user.
*don’t forget, your provider file no longer needs to include your credentials as they now exist in the “~/.aws/credentials/” logfile
In summary, there should not be extremely long configuration files that are hard to read. In an additional post, I will explain modules that will reference a “parent/root” module that will point to a source = “location/type of module”(There are many modules you can reference in the Terraform registry). For this example, we will have one ec2 instance ec2(main).tf, and a variable file (variables.tf). Just for future reference the ec2.tf could be named main.tf and include multiple resources that you want to deploy (i.e. VPN, security groups, multiple ec2s, s3 buckets…etc). But for this example, we will keep it simple. By separating the files in this format it helps with re-usability, sharing of code, and future improvements.
Deploying Resources through Terraform — Infrastructure as a Code
It is my opinion, and several of my colleagues and coaches agree…There should only be rare occasions that you write terraform config files from scratch. There are too many resources available (Terraform Registry & Documentation, GitHub, and labs like this) where you can copy and paste the code and change minute details. During this lab I copied and pasted most of my code from the documentation pages for simplicity. Let’s go through each file and explain what it will deploy.
First, let’s check our provider file that will tell Terraform which cloud provider we are deploying resources to. You will see I am using aws, but you may check the Terraform website for other available options. I also only want to deploy resources for this example to the region closest to me which is us-east-1. You can change this your desired region.
Next, let’s review the variables and explain what they will do in the rest of our code. This is a separate config file.
In the above variable, I only want my ec2 instances to be t2.micro. I could place this in the under the resource characteristic instance_type however if I am in a work setting and management wants to change the type of instances, all they would have to do here is change the variable default and run terraform apply and it will deploy a new instance type (t2.medium, large…etc)
Under the next variable iam_names you will see in a few slides that I am making 3 IAM users each of them will be named devuser, stageuser, and produser. I will show you this when we run our terraform plan/apply which user names will change.
*Don’t forget the list numerical values are as such [0 (devuser), 1 (stageuser), 2 (produser)] . You will see testuser [0,1,2] then the name change under the characteristics.
Next, Let’s discuss our resources that will be deployed.
In the first resource block, we will deploy a single ec2 instance. The AMI is region-specific so please choose the one specific to the type and region you want to deploy it in. Now we see that the Instance_type is pulling a value from the variable config file above where we set the default to t2.micro (because its in the free tier).
In the next resource block, we are creating an elastic ip address — named “elastictest” but you can choose whatever name you like.
In the next block, we are associating the elastic ip address just created to our ec2 instance above named “myec2”.
In the next block, we are creating a security group and allowing for TLS (TLS is explained below, and don’t worry I had to look it up as well), and naming our security group practice-security-group. We are naming our security group so that we can decipher which one belongs to this code.
The final block is the ingress block which controls what incoming traffic will be allowed to connect to our instance. Since security groups are stateful if you do not have ingress you will not be able to connect to your instance. I chose SSL port 443 and in the CIDR range I point to the above block aws_eip named elastic test, and my specific public ip address hence the /32.
Lets now move on to the last resources we will deploy in this example…IAM.
* Now I had some difficulty here with one error and requiring a password reset that I never figured out but continuing on…
The first resource block in the config file we are creating 3 (count = 3) IAM users. The name of these users will pull a value from the variable config file “iam_names”. The count.index will point to which one of the three users will receive the name dev, stage, or produser.
The next resource block will create an iam account password policy requiring 8 minimum characters, include at least one lowercase, uppercase and allow the user to change the password. * I tried to force a password reset in the user profile resource block but I could not figure out how to point to the “name =” value in the aws_iam_user argument block.
Now let’s try to terraform plan & apply and see the details of the deployment. Ensure you are in the proper working directory on your terminal and have run “terraform init” to initialize the backend and make sure you have the most up to date version based on your provider.
There will be some of the output I will skip because it will not be known until after apply.
Above you can see where the testusers created originally would have had a name and value of testuser[0,1,2] that will be renamed dev, stage, produser. You can also see where our instance_type value was pulled correctly from the variable configuration file “t2.micro.”
In the screen above you will see our created security and its name will be created and named properly along with 8 resources that will be created and added to our account. Now enter “terraform apply” and enter yes to test the deployment. Next, you will need to log in to your AWS account to verify all of the resources provisioned properly.
*After completing all of this I realized that I did not associate the instance created with a security group. But you can enter this in your resource config file and apply it and the 1 change will update or you can do it manually in aws but this is not a recommended best practice.
Modules: Briefly Explained
Above: The red rectangle is the location of the module as it relates to your directory/file system or github location. The terraform configuration will reference this when pulling input/output values to reference a resource.
Any criticism is welcomed!