Embracing Cloud Technologies: Infrastructure Deployment and Management Best Practices
The rapid rise in cloud adoption has revolutionized the IT industry (and all other business areas that may rely on IT as a support tool) in several ways. Among the aspects of Cloud Technologies that have boosted development, we can list the decrease in the time to achieve a fully deployed state for the application. Web Services and complex stacks like Kubernetes clusters and databases, can be deployed in minutes. Another aspect of cloud that has improved the way we deploy web applications is the fast scalability that Cloud Providers offer.
Although the adoption of Cloud technology has brought many benefits, it is imperative for organizations to adhere to best practices and implement robust security measures to avoid undesirable consequences.
In this post, we will explore the different approaches used for cloud infrastructure deployment (like ClickOps and infra deploy from local environments), their associated risks, and how the adoption of more secure practices like OIDC (OpenID Connect) can enhance security and centralize the infrastructure deployment and management process.
Cloud Infra Deployment: Traditional Approaches
- ClickOps: Many organizations initially relied on manual configuration techniques, popularly known as ClickOps, to deploy infrastructure on the cloud. This approach involved navigating through complex web interfaces, configuring services, and managing resources manually. Although ClickOps offered simplicity, it lacked scalability and reproducibility, making it a time-consuming and error-prone method. ClickOps also makes processes like infrastructure auditing much more difficult. Example of scenario: suppose that, in a given organization, we have multiple environments of the same application to be deployed. Through ClickOps alone, we would need to write down all of the steps and values to be filled in each field of the Cloud Provider interfaces, to deploy each resource. Additionally, for applications that have dependencies among resources, the order of deployment of resources also needs to be kept the same to avoid problems after deployment. Even though all the steps are accurately followed in the same way in all the required environments (like dev => prod environments), this would still be a complex and error-prone technique to deploy infrastructure.
- Infrastructure as Code (IaC): Recognizing the limitations of ClickOps, organizations turned to Infrastructure as Code (IaC) solutions such as Terraform or the Serverless Framework. Let us take Terraform as an example for description here. With Terraform, developers can define their infrastructure using declarative code, enabling consistent and repeatable deployments across cloud providers. Terraform can also manage the proper order of deployment of resources in the majority of scenarios. Although offering significant improvements over ClickOps, IaC tools must be used with caution and best practices. Otherwise, using IaC can bring even more risks and exposure to an organization, when compared to using ClickOps (especially when IaC tools are used in local environments, and permanent Admin access credentials are being kept in local devices in organizations adopting BYOD, or Bring Your Own Device).
Addressing Security Risks: An Example of Implementation
There are numerous techniques that can be adopted by organizations to improve the security of their cloud environments, especially when it comes to infrastructure deployment and management. Here we will cover two aspects:
- Centralization of infrastructure deployment environment
- Adoption of the OIDC as an authentication protocol
Let us give a practical example of how the two practices above can be used in an application. We will use, as examples to describe the process: 1) AWS as the Cloud Provider, 2) Bitbucket as the Git-based version control tool as well as the CI/CD pipeline platform, through Bitbucket Pipelines. We will not cover, in this post, specific information about the mechanism behind OIDC. For a more descriptive approach of the protocol, have a look at the Official Documentation. We also mention that using OIDC with other tools like GitHub Actions instead of Bitbucket Pipelines is also possible, see the GitHub Documentation for this part).
Following the guide in the Bitbucket Pipelines docs, the first thing we should do on the Bitbucket end to use OIDC to deploy infrastructure to AWS is to change the bitbucket-pipelines.yml file according to this:
image: amazon/aws-cli
pipelines:
default:
- step:
name: Get secrets for deployment
oidc: true
max-time: 5
script:
- aws sts assume-role-with-web-identity --role-arn arn:aws:iam::XXXXXX:role/projectx-build --role-session-name build-session --web-identity-token "$BITBUCKET_STEP_OIDC_TOKEN" --duration-seconds 1000 >> awssecrets
The YAML code above carries several information. Let us describe in detail some of them below:
- oidc: true => This is used to inform Bitbucket Pipelines that the step needs OIDC to do the actions in the step (in this case, fetch AWS credentials)
- max-time: 5 => This line establishes the maximum execution timeof the step, in minutes. So in this case, we have 5 minutes of maximum execution time.
- The script line contains an AWS CLI command. The aws sts assume-role-with-web-identity command utilizes the AWS CLI to assume a specific IAM role using web identity authentication. The — role-arn specifies the ARN (Amazon Resource Name) of the IAM role to assume, — role-session-name provides a name for the assumed role session, and — web-identity-token passes the OIDC token obtained from Bitbucket Pipelines (note that the OIDC token is stored as a secret in Bitbucket, which increases the security of the setup when compared to the local storage of credentials we mentioned in the previous section). Finally, — duration-seconds specifies the duration of the assumed role session in seconds. The last part, namely >> awssecrets, indicates that we will put the credentials inside a file called awssecrets. Those credentials can then be used in posterior steps of the pipeline by using the artifacts resource of Bitbucket pipelines, to be inserted just below the scripts declaration in the YAML above. The artifacts enable us to store the file and use it in other steps (like Terraform init, plan and deploy in case we are using Terraform as the IaC tool).
The documentation part of Bitbucket Pipelines already guides us to define the OIDC connection on the Bitbucket side. So we refer to that page for more details and latest version documentation on that configuration part.
Finally, we need to setup the AWS account security configuration, for the account to which we will deploy the resources using Bitbucket Pipelines. This step needs to be done so that AWS can verify the identity of the Bitbucket Pipelines CI/CD run and authorize Bitbucket Pipelines to fetch the credentials and assume the given execution role. The AWS setup part is also included in the Bitbucket Documentation, in this reference.
Assuming we have succeeded at implementing the OIDC above for Bitbucket Pipelines and also that we have successfully configured the AWS account environment to also allow Bitbucket to fetch the credentials for Infrastructure deployment, we now have a more secure way of deploying infrastructure. The last step to be done is to remove the permissions for creating and changing resources, from the developers role in the organization. The recommended approach is to provide one role with only Read Access to resources in AWS, for the developers of the organization. This will allow developers to see resources from AWS CLI or Console, but will not let them change infrastructure from local environment through the IaC tool / AWS CLI or the AWS Console.
Final Remarks and Conclusion
To conclude this post, we would like to summarize the main ideas we discussed:
- ClickOps way of defining Cloud resources
- Brief summary of the negative points of ClickOps
- Introduction to using IaC and benefits
- Brief summary of the negative points of locally using IaC
- Advanced techniques for centralized Infra deploy with OIDC as example
- Final thoughts and Read-Only permission adjustment for individuals
Finally, let us present here a final illustration of the architecture modifications involved in the adoption of OIDC (Figure 2), instead of the initial configuration we described in the early sections (Figure 1):