Skip to main content

Automating SSL Certificates for AVEVA PI System with Terraform, Ansible, and CI/CD

· 6 min read
Tyler Engelhardt
Founder of Mainely Innovations

Automation Overview

Managing SSL certificates across dozens of PI Vision and PI Web API servers can be a complex and error-prone process. This blog post explores a comprehensive approach to automate SSL certificate provisioning and deployment using Terraform, Ansible, and CI/CD pipelines, specifically focusing on AWS Private CA and ACM for certificate management.

Deploying SSL certificates is a critical yet challenging aspect of managing secure connections across multiple servers. Manual processes can be prone to errors and time-consuming. Automation becomes essential to streamline the deployment, rotation, and overall management of SSL certificates. In this context, we'll delve into leveraging the power of AWS ACM along with Terraform and Ansible for an efficient and automated solution.

Note: The Terraform modules discussed here are advanced versions of publicly available modules. Depending on your environment, additional adjustments may be required. Feel free to reach out for assistance in implementing the solution in your specific context.

Get Started with Terraform

The process begins with generating a certificate from a private AWS Certificate Authority. Typically, the Private CA is located in a separate AWS account from the application deployments and will require being exported and imported as a part of the deployment process.

We can perform the provisioning of the SSL certificate using Terraform with JSON to not only define the certificate to create, but also define the values required for the CI/CD process that will export the certificate before packaging it as a PFX and copying it to the target AWS environment.

This certificate will secure the AWS load balancer and play a crucial role in configuring IIS bindings for PI Vision and the Admin Utility for PI Web API. Here's a breakdown of the Terraform configuration:

{
"Name": "ACM-CERT-PI_WEB_API",
"DomainName": "api.pi.mainely.io",
"AlternateNames": ["pi-api-01a.mainely.io", "pi-api-01b.mainely.io"],
"PrivateAuthorityArn": "{{PrivateCertAuthorityArn}}",
"ExportConfig": {
"Export": true,
"Credentials": {
"SecretRole": "arn:aws:iam::<account-id>:role/pi/prod/DMZ-USE1-PRD-PI-ROLE-SECRET",
"AcmRole": "arn:aws:iam::<account-id>:role/pi/prod/DMZ-USE1-PRD-PI-ROLE-CICD",
"Secret": "DMZ-USE1-PRD-PI-SECRET-ENVIRONMENT",
"Key": "SSLPasswordWebAPI"
},
"Import": {
"Secret": "DMZ-USE1-PRD-PI-SECRET-CERTIFICATES",
"Prefix": "dmz-prd-pi-api"
},
"Upload": {
"Bucket": "my-private-s3-bucket",
"Prefix": "PIServer/Environment/DMZ/Production/SSL/"
}
}
}

This configuration not only defines the certificate but also outlines the necessary values for the subsequent CI/CD process responsible for exporting, importing, and uploading the certificate to the target AWS account. The ExportConfig object is not used with terraform for certificate provisioning.

Importing Certificate into AWS ACM

Once the certificate is provisioned, the next step involves importing it into the AWS account designated for the application. This process is made straightforward through the CI/CD process. The configuration snippet below exemplifies the import process through the required terraform JSON configuration:

{
"Name": "ACM-CERT-PI_WEB_API",
"Import": {
"Secret": "Certificates",
"PrivateKey": "dmz-prd-pi-api.key",
"CertificateBody": "dmz-prd-pi-api.cert",
"CertificateChain": "dmz-prd-pi-api.chain"
}
}

In the configuration above, Secret refers to an AWS secret defined for the environment and is linked by referencing the terraform state of the secret deployment. Since JSON and terragrunt are used for the deployment, we can reference the resource via state rather than explicitly defining the secret name here. The other parameters of the Import block are used to define the 3 portions of the certificate that will be imported into ACM.

Bind Certificate to Load Balancer

With the SSL certificate successfully imported, the next step is to bind it to a load balancer. While the specific details of target groups, security groups, subnets, and stickiness configurations are omitted for brevity, the critical aspect is referencing the imported ACM certificate in the load balancer configuration. An example is provided below:

{
"Name": "ELB-PI_WEB_API",
"Type": "application",
"Internal": true,
"DeletionProtection": false,
"EnableHttp2": true,
"Listeners": {
"Default": {
"Type": "forward",
"Port": 443,
"Protocol": "HTTPS",
"Certificate": "PIWebAPI",
"SslPolicy": "ELBSecurityPolicy-2016-08"
}
}
}

This configuration ensures the successful binding of the imported ACM certificate to the AWS application-type load balancer through referencing the terraform state of the ACM certificate, rather than specifying the ARN directly.

Deploying Certificates with Ansible

Ansible plays a pivotal role in deploying SSL certificates to either the PI Web API or PI Vision. Updating PI Vision involves a straightforward IIS binding update, while updating PI Web API requires a more detailed process. The following illustrates the Jinja configuration for updating the SSL thumbprint in the required InstallationConfig.json configuration file for the PI Web API using Ansible:

{
...
"SslCertificateThumbprint": "{{ssl_thumbprint_pi_webapi}}"
...
}

With the configuration file updated, the PI Web API installer can be run with Ansible to enforce the updates. The ssl_thumbprint_pi_webapi can be dynamically obtained or statically defined, depending on your deployment strategy.

Automation with CI/CD Pipeline

The entire process can be orchestrated and automated through a continuous integration and deployment (CI/CD) pipeline. Popular services like Azure DevOps, GitLab, and GitHub provide robust pipeline capabilities. With AWS, the Private CA is typically located in an account external to the application which drives the need for importing certificates to other accounts for usage within ACM.

The simplified YAML pipeline declaration below covers key stages, including planning, building, exporting certificates, and importing certificates:

stages:
- stage: Management_Plan
jobs:
- deployment: Management
- template: ./jobs/terragrunt-plan.yml

- stage: Management_Build
dependsOn: Management_Plan
condition: eq(dependencies.Management_Plan.result,'Succeeded')
jobs:
- deployment: Management
- template: ./jobs/terragrunt-apply.yml
- job: Publish
steps:
- task: PublishBuildArtifacts@1
displayName: Publish Certificates
inputs:
artifactName: certificates
pathToPublish: "$(Build.SourcesDirectory)/_env/Certificates"

- stage: Export_Certificates
dependsOn: Management_Build
condition: eq(dependencies.Management_Build.result,'Succeeded')
jobs:
- deployment: Management
- job: Configure
steps:
- task: DownloadPipelineArtifact@2
inputs:
artifact: certificates
path: "$(Build.SourcesDirectory)/_env/Certificates"
- bash: |
cd .azuredevops/python
python3 ImportCerts.py

This pipeline orchestrates the provisioning, exporting, and importing of SSL certificates, where the python script executes all non-provisioning tasks. However, deployment of the certificates to ACM in another account, a load balancer, or to application deployment will take additional stages or pipelines.

Conclusion

In conclusion, the automation of SSL certificate management for the AVEVA PI System using Terraform, Ansible, and CI/CD pipelines offers a robust and efficient solution. By embracing automation, organizations can streamline deployment processes, reduce errors, and enhance overall productivity. Consider implementing these practices in your environment to optimize SSL certificate management and maximize the benefits of automation.