I'm trying to implement MTLS client authentication using AWS ACM Private CA to issue X.509 client certificates. The certificate and the correlating private key is supposed to be stored in a password protected PKCS#12 file. The private key will also be used by the client to sign data.
If I request a new certificate using aws-acm-sdk
:
RequestCertificateResult response = acm.requestCertificate(new RequestCertificateRequest()
.withCertificateAuthorityArn(CA_ARN)
.withIdempotencyToken("1234")
.withDomainName("localhost.com"));
return response.getCertificateArn();
And then export the it using the arn, I get a certificate, certificateChain and a privateKey as strings.
ExportCertificateResult response = acm.exportCertificate(new ExportCertificateRequest()
.withCertificateArn(certificateArn)
.withPassphrase(ByteBuffer.wrap(password.getBytes())));
String certificate = response.getCertificate();
String certificateChain = response.getCertificateChain();
String privateKey = response.getPrivateKey();
But I'm not able to add any type of identifier that let's me tie the certificate to a user during authentication (I'm using Java and Spring security x509 authentication, which extracts e.g. the subject CN (Common Name) from the certificate which then can be used to identify a user).
If I want to add custom attributes to the certificate, I need to issue a certificate through the aws-acm-pca-sdk
:
IssueCertificateRequest request = new IssueCertificateRequest()
.withCertificateAuthorityArn(CA_ARN)
.withCsr(stringToByteBuffer(getCSR()))
.withTemplateArn("arn:aws:acm-pca:::template/EndEntityClientAuthCertificate_APIPassthrough/V1")
.withSigningAlgorithm(SigningAlgorithm.SHA256WITHRSA)
.withValidity(new Validity()
.withValue(365L)
.withType(ValidityPeriodType.DAYS))
.withIdempotencyToken(userId)
.withApiPassthrough(new ApiPassthrough()
.withSubject(new ASN1Subject()
.withCustomAttributes(List.of(
new CustomAttribute()
.withObjectIdentifier("1.3.6.1.4.1") // CustomOID
.withValue("userId")))));
return acmPca.issueCertificate(request).getCertificateArn();
But if I use the sdk to get the certificate, it doesn't contain any private key.
GetCertificateResult response = acmPca.getCertificate(new GetCertificateRequest()
.withCertificateAuthorityArn(CA_ARN)
.withCertificateArn(certificateArn));
String certificate = response.getCertificate();
String certificateChain = response.getCertificateChain();
So, when I read documentation I found that I need to import it to ACM in order to export
it and get the private key.
But in order to import it to ACM I also need to provide the private key..
But as I understand it, the private key should be used when issuing the certificate in the first place? Should I create a new public/private key pair using KMS or what am I supposed to do?
Im confused.. Please help!
I had misinterpreted the responsibility of the PCA.
The PCA is only responsible for issuing certificates, not keys or even CSR (Certificate Signing Requests).
I assumed that the CSR were created by PCA, so the getCSR()
method actually fetched the CA's CSR from PCA, while the actual CSR should be generated internally using a private key which has been generated either programmatically or using KMS.