Currently, the aws_acmpca_certificate_authority
resource exists (thanks @bflad) but it leaves the CA in an unusable state, pending a signature from a parent CA of some sort. Right now we have to go inject that signed certificate ourselves and then the ACM PCA is usable. Having a terraform "virtual resource" for this process would streamline this process because then we can just rerun terraform.
Furthermore, for testing, we could also use terraform's nice TLS module to sign the ACMPCA CSR automatically as part of the workflow, and then proceed for example to generate certificates with something like @TFaga's https://github.com/terraform-providers/terraform-provider-aws/issues/5550.
aws_acmpca_certificate_authority_signature
(I don't know what to call it, really)resource "aws_acmpca_certificate_authority" "pca" {
...
}
resource "tls_locally_signed_cert" "test-zomg" {
cert_request_pem = "${aws_acmpca_certificate_authority.pca.certificate_signing_request}"
...
}
resource "aws_acmpca_certificate_authority_signature" "sig" {
certificate = "${tls_locally_signed_cert.test-zomg.cert_pem}"
}
For what its worth, the ACMPCA SDK refers to this as the "Certificate Authority Certificate" so we would likely prefer to match the upstream naming.
Looking at the SDK call, it seems we will need to support three arguments:
resource "aws_acmpca_certificate_authority_certificate" "example" {
certificate_authority_arn = "${aws_acmpca_certificate_authority.example.arn}"
certificate = ""
certificate_chain = ""
}
Yeah, I was telling myself that's what the actual issued certificate resources were gonna be called but I guess those would more likely be aws_acmpca_certificate
.
One potential weirdness is the deletion behavior of this resource, because I don't think ACM PCA lets you "decertify" a PCA, so resource deletion would likely be a no-op.
How are others currently handling activating their AWS CAs with Terraform until this issue is resolved?
@CharlieC3 I think an option here would be to use a null resource with localexec and running the aws acm-pca import-certificate-authority-certificate
command via the cli.
@sarkis
Thanks, that's what I ended up doing. I found out you also need to manually set the permissions on the CA once the cert is imported as well:
resource "null_resource" "private_root_ca_import" {
provisioner "local-exec" {
command = <<EOT
aws acm-pca import-certificate-authority-certificate \
--certificate-authority-arn ${aws_acmpca_certificate_authority.private_ca.arn} \
--certificate '${tls_locally_signed_cert.private_ca_cert.cert_pem}' \
--certificate-chain '${tls_self_signed_cert.private_root_ca_cert.cert_pem}'
EOT
}
provisioner "local-exec" {
command = <<EOT
aws acm-pca create-permission \
--certificate-authority-arn ${aws_acmpca_certificate_authority.private_ca.arn} \
--principal 'acm.amazonaws.com' \
--source-account '${data.aws_caller_identity.current.account_id}' \
--actions 'IssueCertificate' 'GetCertificate' 'ListPermissions'
EOT
}
}
@CharlieC3 I think an option here would be to use a null resource with localexec and running the
aws acm-pca import-certificate-authority-certificate
command via the cli.
alternative workaround if you want to install a Type = ROOT
ca cert, using some dummy example values
(this is the same way that the console GUI does it if you choose "install ca cert" after creating the PCA - I checked the API calls it makes with dev tools)
...
type = "ROOT"
provisioner "local-exec" {
command = <<EOT
export PCA_ARN="${aws_acmpca_certificate_authority.pca.arn}"
export PCA_CSR="${aws_acmpca_certificate_authority.pca.certificate_signing_request}"
export VALIDITY_DAYS=3650
${path.module}/scripts/activate-root-pca.sh
EOT
}
#activate-root-pca.sh
ROOT_CA_CERT_ARN=$(aws acm-pca issue-certificate \
--certificate-authority-arn "$PCA_ARN" \
--csr "$PCA_CSR" \
--signing-algorithm SHA256WITHRSA \
--validity "Value=$VALIDITY_DAYS,Type=\"DAYS\"" \
--template-arn "arn:aws:acm-pca:::template/RootCACertificate/V1" \
--output json \
| jq -r '.CertificateArn')
sleep 10
ROOT_CA_CERT=$(aws acm-pca get-certificate \
--certificate-authority-arn "$PCA_ARN" \
--certificate-arn "$ROOT_CA_CERT_ARN" \
--output json \
| jq -r '.Certificate' \
| sed 's/\\n/\n/g') # swap literal newline characters for newlines
aws acm-pca import-certificate-authority-certificate \
--certificate-authority-arn "$PCA_ARN" \
--certificate "$ROOT_CA_CERT"
needless to say, I'm hopeful to see https://github.com/terraform-providers/terraform-provider-aws/pull/13684 etc. get merged :)
Ran into this issue https://github.com/aws/aws-cli/issues/5011 when trying the above approach.
Went with this instead:
resource "aws_acmpca_certificate_authority" "example" {
provisioner "local-exec" {
command = "./activate-pca.sh --common-name '${local.ca_root_name}'"
interpreter = ["/bin/bash"]
}
certificate_authority_configuration {
key_algorithm = "RSA_4096"
signing_algorithm = "SHA512WITHRSA"
subject {
common_name = local.ca_root_name
}
}
./activate-pca.sh
# Skipping arg parsing
CA_ARN=$(
aws acm-pca list-certificate-authorities \
--output text \
--query "CertificateAuthorities[?CertificateAuthorityConfiguration.Subject.CommonName==\`${COMMON_NAME}\`].Arn"
)
CA_INFO=$(aws acm-pca describe-certificate-authority --certificate-authority-arn "$CA_ARN")
CA_STATUS=$(echo "$CA_INFO" | jq -r '.CertificateAuthority.Status')
if [[ "$CA_STATUS" != "PENDING_CERTIFICATE" ]]; then
echo "Error: CA is '$CA_STATUS', cannot activate"
exit 1
fi
CA_CSR=$(
aws acm-pca get-certificate-authority-csr \
--certificate-authority-arn "${CA_ARN}" \
--output text
)
and then as the above example.
Most helpful comment
@sarkis
Thanks, that's what I ended up doing. I found out you also need to manually set the permissions on the CA once the cert is imported as well: