Skip to content

Commit db64a12

Browse files
authored
Merge pull request #166 from ts-amz/add-acmpca-to-certificatevendor
Add acmpca to certificatevendor
2 parents 556bfd2 + a2417b5 commit db64a12

File tree

14 files changed

+963
-44
lines changed

14 files changed

+963
-44
lines changed

source/packages/services/certificatevendor/README.md

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44

55
The certificate vendor manages the rotation of certificates involving a number of moving parts across CDF and AWS IoT.
66

7-
There are two flows for certificate rotation. In the fist case, device certificates are pre-created and registered before the rotation request. In this case the device requests a new certificate and is vended an S3 presigned URL in order to download the certificate package. In the second case, the device provides the certificate vendor module a CSR. In this way the device can request an updated certificate while keeping the private key on the device. The certificate vendor then uses a CA certificate registered with AWS IoT to create a device certificate from the CSR and return this certificate to the device.
7+
There are two flows for certificate rotation. In the fist case, device certificates are pre-created and registered before the rotation request. In this case the device requests a new certificate and is vended an S3 presigned URL in order to download the certificate package. In the second case, the device provides the certificate vendor module a CSR. In this way the device can request an updated certificate while keeping the private key on the device.
8+
There are two options for CSR case. One option is to use ACM PCA to issue the certificate, and another option is to create a certificate from a CA certificate registered with AWS IoT, and CA private key sorted in EC2 Parameter store.
89

910
## Architecture
1011

@@ -20,8 +21,41 @@ A certificate package comprising of the certificate, public key and private key
2021

2122
### Certificate Creation with a device CSR
2223

24+
#### Certiicate Creation with CA private key
25+
2326
A CA certificate needs to be registered with AWS IoT. In addtion, the CA private key needs to be encrypted and stored in EC2 Parameter store so the certificate vendor module can sign device certificates using the CA.
2427

28+
#### Certificate Creation from ACMPCA
29+
30+
AWS Private Certificate Authority needs to be prepared and private CA needs to be created as prerequisite.
31+
The private CA needs to be registered with AWS IoT. The example registration step is as follows.
32+
33+
```
34+
1. Create Verification CSR
35+
$ openssl genrsa -out verificationCert.key 2048
36+
2. Get IoT Core Registration Code
37+
$ aws iot get-registration-code
38+
3. Create CSR. Insert the registration code in Common Name.
39+
$ openssl req -new -key verificationCert.key -out verificationCert.csr
40+
4. Request to issue certificate to ACM PCA for verification. It will return certificate ARN.
41+
$ aws acm-pca issue-certificate \
42+
--region ap-northeast-1 \
43+
--certificate-authority-arn arn:aws:acm-pca:ap-northeast-1:XXXXXXXXXXX:certificate-authority/12345678910 \
44+
--csr fileb://verificationCert.csr \
45+
--signing-algorithm SHA256WITHRSA \
46+
--validity Value=365,Type="DAYS"
47+
5. Call get-certificate to get certificate
48+
$ aws acm-pca get-certificate --region ap-northeast-1 \
49+
--certificate-authority-arn arn:aws:acm-pca:ap-northeast-1:XXXXXXXXXXX:certificate-authority/12345678910 \
50+
--certificate-arn arn:aws:acm-pca:ap-northeast-1:XXXXXXXXXXX:certificate-authority/12345678910
51+
6. Store the Certificate as verify.crt. Transform \n into return code.
52+
7. Register to IoT Core by using Verification CSR and Root CA certification.
53+
$ aws iot register-ca-certificate --ca-certificate file://Certificate.pem --verification-certificate file://Verify.crt --region ap-northeast-1 --set-as-active
54+
```
55+
56+
The registered CA Certificate ID and PCA Authority Arn need to be entered
57+
in the inquiry prompt in the installer or request body as parameters.
58+
2559
## Deployment
2660

2761
The following resources are automatically created as part of the deployment and utilized by this flow:
@@ -139,6 +173,40 @@ MQTT PUBLISH BODY:
139173
}
140174
```
141175

176+
Example MQTT message body sent from the device to the AWS IoT Gateway to retrieve a certificate based on a provided CSR. That use ACM PCA to issue a new certificate:
177+
178+
```sh
179+
MQTT SUBSCRIBE TOPIC: cdf/certificates/thing001/get/+
180+
MQTT PUBLISH TOPIC: cdf/certificates/thing001/get
181+
MQTT PUBLISH BODY:
182+
{
183+
"csr":"-----BEGIN CERTIFICATE REQUEST-----\nCSR CONTENT\n-----END CERTIFICATE REQUEST-----"
184+
"acmpcaParameters" :{ // If not specified, the values specified in the installer will be used.
185+
// Mandatory. Either provide the ACM PCA CA ARN to issue the device certificate,
186+
// or an alias that points to said AWS ACM PCA CA ARN:
187+
"acmpcaCaArn": "?",
188+
"acmpcaCaAlias": "?",
189+
190+
// Mandatory. Either provide the AWS IoT CA ID of the ACM PCA CA registered with AWS IoT,
191+
// or an alias that points to said AWS IoT CA ID:
192+
"awsiotCaID": "?",
193+
"awsiotCaAlias": "?",
194+
195+
// Optional. Certificate information to apply:
196+
"certInfo": { // optional.
197+
"commonName": "?", // optional
198+
"organization": "?", // optional
199+
"organizationalUnit": "?", // optional
200+
"locality": "?", // optional
201+
"stateName": "?", // optional
202+
"country": "?", // optional
203+
"emailAddress": "?", // optional
204+
"daysExpiry": ? // optional
205+
}
206+
}
207+
}
208+
```
209+
142210
Upon receiving the request, the CDF Certificate Vendor module validates that the device is approved to received a new certificate. The registry to be used, whether the AWS IoT Device Registry or the CDF Asset Library module, is configured as part of the initial deployment. This reference implementation determines whether something is approved by checking its existence. If these behavior needs to be enhanced, refer to `src/registry/assetlibrary.service.ts` / `src/registry/deviceregistry.service.ts`
143211

144212
If approved, the CDF Certificate Vendor module checks for the presence of a CSR in the request. If provided, the CSR is used to create a new device certificate and returned to the device. If not present, teh CDF Certificate Vendor module proceeds to download the S3 Object Metadata associated with the certificate package to retrieve the `certificateId`, activates the certificate within AWS IoT, then constructs and returns a pre-signed url to the device for secure downloading of the certificate package. Finally the device status is updated to activated.

source/packages/services/certificatevendor/infrastructure/cfn-certificatevendor.yml

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,25 @@ Parameters:
6464
RotatedCertificatePolicy:
6565
Type: String
6666
Default: ''
67+
AcmpcaEnabled:
68+
Type: String
69+
Default: 'false'
70+
AcmpcaCaArn:
71+
Type: String
72+
Default: ''
73+
AcmpcaSigningAlgorithm:
74+
Type: String
75+
Default: 'SHA256WITHRSA'
76+
ACMPCACrossAccountRoleArn:
77+
Description: If ACM PCA functionality is to be used, and a ACM PCA is located within a different AWS Account, specify the cross-account IAM Role ARN.
78+
Type: String
79+
Default: ''
6780

6881
Conditions:
6982
ThingGroupNameProvided: !Not [!Equals [!Ref ThingGroupName, '']]
7083
KmsKeyProvided: !Not [!Equals [!Ref KmsKeyId, '']]
7184
KmsKeyNotProvided: !Equals [!Ref KmsKeyId, '']
72-
85+
ACMPCACrossAccountAccessRequired: !Not [!Equals [!Ref ACMPCACrossAccountRoleArn, '']]
7386
Resources:
7487
MQTTGetRule:
7588
Type: 'AWS::IoT::TopicRule'
@@ -149,6 +162,7 @@ Resources:
149162
ManagedPolicyArns:
150163
- !Ref ApplicationPolicies
151164
- !Ref ApplicationCsrPolicies
165+
- !Ref ACMPolicy
152166
- arn:aws:iam::aws:policy/AWSLambdaExecute
153167
- arn:aws:iam::aws:policy/AWSXrayWriteOnlyAccess
154168
Condition: KmsKeyProvided
@@ -261,6 +275,25 @@ Resources:
261275
Effect: Allow
262276
Resource: !Sub 'arn:aws:iot:${AWS::Region}:${AWS::AccountId}:cert/*'
263277

278+
ACMPolicy:
279+
Type: AWS::IAM::ManagedPolicy
280+
Properties:
281+
Description: 'cdf-bulkcerts policy for accessing ACM PCA'
282+
Path: '/cdf/provisioning/'
283+
PolicyDocument:
284+
Version: '2012-10-17'
285+
Statement:
286+
- Action:
287+
- 'acm-pca:IssueCertificate'
288+
- 'acm-pca:GetCertificate'
289+
Effect: Allow
290+
Resource: '*'
291+
# optional cross-account role access for ACM PCA
292+
- Fn::If:
293+
- ACMPCACrossAccountAccessRequired
294+
- !Ref ACMPCACrossAccountRoleArn
295+
- Ref: AWS::NoValue
296+
264297
LambdaFunction:
265298
Type: AWS::Serverless::Function
266299
Properties:
@@ -287,7 +320,11 @@ Resources:
287320
AWS_S3_CERTIFICATES_BUCKET: !Ref BucketName
288321
CERTIFICATES_CACERTIFICATEID: !Ref CaCertificateId
289322
POLICIES_ROTATEDCERTIFICATEPOLICY: !Ref RotatedCertificatePolicy
323+
ACMPCA_ENABLED: !Ref AcmpcaEnabled
324+
ACMPCA_CA_ARN: !Ref AcmpcaCaArn
325+
ACMPCA_SIGNING_ALGORITHM: !Ref AcmpcaSigningAlgorithm
290326
AWS_ACCOUNTID: !Ref AWS::AccountId
327+
ACM_PCA_CROSS_ACCOUNT_ROLE_ARN: !Ref ACMPCACrossAccountRoleArn
291328
Tracing: Active
292329

293330
IotEndpoint:

source/packages/services/certificatevendor/src/certificates/certificates.models.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,28 @@ export interface CertificateRequestModel {
1616
certId: string;
1717
csr?: string;
1818
previousCertificateId?: string;
19+
acmpcaParameters?: ACMPCAParameters;
20+
}
21+
22+
export interface ACMPCAParameters {
23+
acmpcaCaArn?: string;
24+
acmpcaCaAlias?: string;
25+
26+
awsiotCaID?: string;
27+
awsiotCaAlias?: string;
28+
29+
certInfo?: CertInfo;
30+
}
31+
32+
export interface CertInfo {
33+
commonName?: string;
34+
organization?: string;
35+
organizationalUnit?: string;
36+
locality?: string;
37+
stateName?: string;
38+
country?: string;
39+
emailAddress?: string;
40+
daysExpiry?: number;
1941
}
2042

2143
export interface CertificateResponseModel {

source/packages/services/certificatevendor/src/certificates/certificates.service.spec.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ let mockedIot: AWS.Iot;
2121
let mockedIotData: AWS.IotData;
2222
let mockedS3: AWS.S3;
2323
let mockedSSM: AWS.SSM;
24+
let mockedACMPCA: AWS.ACMPCA;
2425
const accountId = '12345678';
2526
const region = 'us-west-2';
2627
const s3Bucket = 'myBucket';
@@ -37,6 +38,9 @@ const useDefaultPolicy = true;
3738
const rotateCertPolicy = 'UnitTestDevicePolicy';
3839
const certificateExpiryDays = 100;
3940
const deletePreviousCertificate = false;
41+
const acmpcaCaArn = 'arn:aws:acm-pca:ap-northeast-1:12345678910:certificate-authority/abcdefghi';
42+
const acmpcaEnabled = false;
43+
const acmpcaSigningAlgorithm = 'SHA256WITHRSA';
4044
const certId = 'cert123456';
4145
let defaultPolicyInstance: CertificateService;
4246
let inheritPolicyInstance: CertificateService;
@@ -59,6 +63,7 @@ describe('CertificatesService', () => {
5963
mockedIot = new AWS.Iot();
6064
mockedIotData = new AWS.IotData({ endpoint: 'mocked' });
6165
mockedSSM = new AWS.SSM();
66+
mockedACMPCA = new AWS.ACMPCA();
6267

6368
const mockedS3Factory = () => {
6469
return mockedS3;
@@ -72,6 +77,9 @@ describe('CertificatesService', () => {
7277
const mockedSsmFactory = () => {
7378
return mockedSSM;
7479
};
80+
const mockedAcmpcaFactory = () => {
81+
return mockedACMPCA;
82+
};
7583

7684
defaultPolicyInstance = new CertificateService(
7785
accountId,
@@ -90,11 +98,15 @@ describe('CertificatesService', () => {
9098
rotateCertPolicy,
9199
certificateExpiryDays,
92100
deletePreviousCertificate,
101+
acmpcaCaArn,
102+
acmpcaEnabled,
103+
acmpcaSigningAlgorithm,
93104
mockedRegistryManager,
94105
mockedIotFactory,
95106
mockedIotDataFactory,
96107
mockedS3Factory,
97-
mockedSsmFactory
108+
mockedSsmFactory,
109+
mockedAcmpcaFactory
98110
);
99111

100112
inheritPolicyInstance = new CertificateService(
@@ -114,11 +126,15 @@ describe('CertificatesService', () => {
114126
rotateCertPolicy,
115127
certificateExpiryDays,
116128
deletePreviousCertificate,
129+
acmpcaCaArn,
130+
acmpcaEnabled,
131+
acmpcaSigningAlgorithm,
117132
mockedRegistryManager,
118133
mockedIotFactory,
119134
mockedIotDataFactory,
120135
mockedS3Factory,
121-
mockedSsmFactory
136+
mockedSsmFactory,
137+
mockedAcmpcaFactory
122138
);
123139
});
124140

0 commit comments

Comments
 (0)