In part 1 of this blog series, we overviewed the different tools  that would be used as you go up the stack from infrastructure to application. In this blog, we will be provisioning our Infrastructure as Code (IaC) using Terraform, Ansible, Jenkins and GitHub. First, we will set up our development environment with all the tools needed for this deployment. Then we will review our Terraform configuration files and Ansible playbooks in detail.

As always, your development environment may differ from what is being used in this series, but all the Dev tools we will be using are available on Microsoft, Mac, and Linux operating systems. In our case, we will be using Ubuntu 20.04 to run all our DevOps tools.

We will deploy the latest versions of Terraform, Ansible, AWS CLI, Docker, Jenkins and kubectl on our DevBox. Then we create a GitHub repository for source code management and version control of our infrastructure. We will be using the Cloud Native Security SPOT-ON Series repository in this series. The first thing we are going to do is create a feature branch called infra. We are going to use feature branches to merge our code into the main branch, which is our production branch. When changes are made to the main branch, the build will be triggered by Jenkins. For each SPOT-On episode that we create, there will be a feature branch associated with it. For example, in the next episode we will deploy our applications, so we will create another feature branch named apps and merge into main.

Cloud native security

Video demo for “Setting up the Dev Environment”

In the next section we will have a detailed look at the installation. I have also created a demo video for those of you who prefer to watch instead of read. For those who prefer my detailed written instructions, you’ll find them below. Also, don’t worry, this is not the last episode in the series! Next up, we will use GitOps and CI/CD to build and deploy the cloud infrastructure. For now, here’s my demo video for this Part 2:

Cisco Secure Cloud Native Security – Part 2.1 – Setting up the Dev Environment

Detailed Instructions

If you are reading this, it means you are interested to learn the details of this set up. Let’s jump right in! First, let us look at Jenkins. We will create a multibranch pipeline named Spot On. We will use the Cloud Native Security SPOT ON Series as our Branch Source and will discover all branches.

Secure Cloud Native

The Build Configuration will be defined by the Jenkinsfile. The Jenkinsfile is the instructions of the pipeline itself. We will dive deeper into the Jenkinsfile in the next section.

Secure Cloud Native

When we save the pipeline job, Jenkins will scan the GitHub repository and find the branches we created. When a build is run it will pull down the code from this repository.

Secure Cloud Native

Now that we have our pipeline integrated with our source code repository, let us look at the infrastructure as code. Looking at the structure of our infra branch we see a Jenkinsfile, which is our Pipeline as Code. We also see Terraform files main.tf, output.tf, and variables.tf. These Terraform configuration files are set at the root of the project, called the Root Module. There is also a modules/infra directory which also has a bunch of Terraform files. This module directory contains the code that will provision the infrastructure.

Secure Cloud Native

Like we said previously, the Jenkinsfile is our Pipeline as Code and provides all the instructions for building our pipeline. Looking at the Jenkinsfile first we define the pipeline agents. In this case we are just using the Jenkins master, but we could have a defined agent for each stage if we would like. Next, we set the environment variables. Here we set the environment name and ID, the AWS access and secret keys, as well as the region, availability zones, SSH key and FTD credentials.

Secure Cloud Native

As you can see some of these variables are defined here on the Jenkinsfile, but some of the variables are referencing the syntax credentials(). Jenkins’ declarative Pipeline uses this helper method which supports secret text, username, and password, as well as secret file credentials. We set these variables in Jenkins on the Manage Jenkins > Manage Credentials page. This way we can pass these secret variables to Terraform securely.

Secure Cloud Native

The next section of the Jenkinsfile is where our stages are defined. For right now, we only have one stage which is Build Environment. Within each stage we have multiple steps. The first step is just echoing Building Environment on the build output. The second step will be a terraform get –update, which is used to update any new Terraform providers added to the project. The third step will initialize all the providers configured in the project. The fourth step will apply the Terraform configuration passing all the variables needed to provision the environment.

Secure Cloud Native

Let us look at the Terraform configuration files. The first file to dive into is main.tf. This file is set at the root of the project, meaning it is in the root module. In this file we define another module named Infrastructure which is sourced from ./modules/infra. You can think of a module as a function in other programming languages. In this case we create a module to deploy our infrastructure and pass the necessary environment variables to this module. Why would we do this? For example, let’s say we have multiple environments, such as Dev, Test, QA, and Prod. We want the deploy each environment with the same exact resources, but the environment variables such as IP addresses, subnets, regions, and zones should be different. We also set our Terraform Providers here in main.tf.

Secure Cloud Native

There is also a variables.tf file located in the root module. These are the same variables we are passing from Jenkins as shown above, we are just declaring them in Terraform.

Then we have the modules/infra directory which is where the infrastructure module config files are located. In this directory we see another main.tf and variables.tf files. This may seem redundant but think of this like how we set global variables and local variables in other programming languages. In this case we are defining variables in the root module and passing them to the infra module, which would be the same as declaring variables globally and passing them variables as arguments to the function.

There are also configuration files for the vpc.tf, ftdv.tf, and eks.tf. Each one of these files provisions their respective configurations. We could put all these configurations into one file but breaking it up makes it easier to read and more modular. There is also a file named ftdv_ansible_deploy.tf. We use this Terraform configuration file to run our Ansible playbooks in a Docker container. These Ansible playbooks are used to configure the Secure Firewall policy we have deployed on one of our EC2 instances.

Secure Cloud Native    Secure Cloud Native

Stay tuned

In the next episode of this series, we will use GitOps and CI/CD to build and deploy the cloud infrastructure. Hope to see you back again!

Please let me know if you have any questions, either in the “comments” section below, or via the GitHub issues.


We’d love to hear what you think. Ask a question or leave a comment below.
And stay connected with Cisco DevNet on social!

LinkedIn | Twitter @CiscoDevNet | Facebook Developer Video Channel



Ed McNicholas

Cybersecurity Technical Solutions Architect

Global Security Sales Organization