CircleCI project to manage a Zentral server osquery configuration using Terraform.
The Terraform state is managed using a S3 Bucket – see terraform s3 backend documentation. You need to create a bucket and decide which key to use (filename) for the state object. The bucket name and key will be passed to the CircleCI workflow as environment variables.
To authenticate with AWS and give the CircleCI pipeline permission to use the state object in the S3 bucket, an OpenID Connect provider must be configured in AWS to verify the JSON tokens signed and passed to the workflow by CircleCI. The tokens are exchanged against standard temporary AWS tokens that can be used by the Terraform S3 backend. See this CircleCI blog post for more details.
A role needs to be created in AWS. This role will be assumed by the CircleCI workflow. Here is an example of the trust policy to use on the role (replace CIRCLE_CI_ORGANIZATION_ID
, CIRCLE_CI_PROJECT_ID
and the federated principal ARN by the correct values):
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::AWS_ACCOUNT_ID:oidc-provider/XXXXXXXX"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"oidc.circleci.com/org/CIRCLE_CI_ORGANIZATION_ID:aud": "CIRCLE_CI_ORGANIZATION_ID"
},
"StringLike": {
"oidc.circleci.com/org/CIRCLE_CI_ORGANIZATION_ID:sub": "org/CIRCLE_CI_ORGANIZATION_ID/project/CIRCLE_CI_PROJECT_ID/user/*"
}
}
}
]
}
This will restrict the access to the role. Only the given project within your CircleCI org will be able to assume it.
The role you have just created needs to get access to the state object key within the S3 bucket. Here is an example of a S3 bucket policy you can use (replace AWS_ACCOUNT_ID
, CIRCLE_CI_AWS_ROLE
, BUCKET_NAME
, BUCKET_KEY
by the correct values):
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::AWS_ACCOUNT_ID:role/CIRCLE_CI_AWS_ROLE"
]
},
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::BUCKET_NAME"
},
{
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::AWS_ACCOUNT_ID:role/CIRCLE_CI_AWS_ROLE"
]
},
"Action": [
"s3:GetObject",
"s3:PutObject",
"s3:DeleteObject"
],
"Resource": "arn:aws:s3:::BUCKET_NAME/BUCKET_KEY"
}
]
}
If you already have a local Terraform state, you can migrate it to the s3 backend using the following command (replace BUCKET_NAME
and `BUCKET_KEY):
terraform init --migrate-state \
--backend-config="bucket=BUCKET_NAME" \
--backend-config="key=BUCKET_KEY"
You also need to get access locally to the S3 bucket. Make sure you have valid AWS_REGION
and AWS_PROFILE
environment variables. You could temporarily change the bucket policy and add the AWS principal you use to authenticate from your local machine. Once the migration is done, tighten the S3 bucket policy and remove the local Terraform state files.
You also need Zentral credentials for the CircleCI workflow. Create a group in Zentral with the required permissions, and create a service account, with an API token. Add the service account to the group.
Variable | Value |
---|---|
AWS_REGION | The AWS region |
AWS_ROLE_ARN | The role that the CircleCI pipeline will assume |
S3_BACKEND_BUCKET | The name of the bucket used by the Terraform S3 backend |
S3_BACKEND_KEY | The key of the object used by the Terraform S3 backend |
ZTL_API_BASE_URL | The base URL for the Zentral API |
ZTL_API_TOKEN | The Zentral API token |