Skip to content

Commit 22a7f2b

Browse files
authored
Feat: Add support to export ACM certificates (#82)
Add support to export ACM certificates to Kubernetes TLS Secrets for ACM private and public certificates.
1 parent 2827c44 commit 22a7f2b

21 files changed

+446
-60
lines changed

README.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,48 @@ Kubernetes Github project.
88

99
[ack-issues]: https://github.com/aws/aws-controllers-k8s/issues
1010

11+
## Getting Started
12+
13+
### Pricing
14+
The ACK service controller for AWS Certificate Manager is free of charge. If you issue an exportable public certificate with AWS Certificate Manager, there is a charge at certificate issuance and again when the certificate renews. Learn more about [AWS Certificate Manager Pricing](https://aws.amazon.com/certificate-manager/pricing/).
15+
16+
[samples]: https://github.com/aws-controllers-k8s/acmpca-controller/tree/main/samples
17+
18+
### Kubernetes Secrets
19+
The ACK service controller for AWS Certificate Manager uses Kubernetes TLS Secrets to store the certificate chain and decrypted private key of [exportable public certificates](https://docs.aws.amazon.com/acm/latest/userguide/acm-exportable-certificates.html). Users are expected to create Secrets before creating Certificate resources. As these resources are created, the Secrets' `tls.crt` will be injected with the base64-encoded certificate and `tls.key` will be injected with the base64-encoded private key associated with the certificate. Users are responsible for deleting Secrets.
20+
21+
In addition, after a certificate is successfully renewed by ACM, the ACK service controller for AWS Certificate Manager will automatically export the renewed certificate again so that the Kubernetes TLS Secret `exportTo` contains the certificate data and private key data of the renewed certificate.
22+
23+
#### Export Certificate
24+
To export an ACM exportable public certificate to a Kubernetes TLS Secret, users must specify the namespace and the name of the Secret using the `exportTo` field of the Certificate resource, as shown below.
25+
26+
```
27+
apiVersion: v1
28+
kind: Secret
29+
type: kubernetes.io/tls
30+
metadata:
31+
name: exported-cert-secret
32+
namespace: demo-app
33+
data:
34+
tls.crt: ""
35+
tls.key: ""
36+
---
37+
apiVersion: acm.services.k8s.aws/v1alpha1
38+
kind: Certificate
39+
metadata:
40+
name: exportable-public-cert
41+
namespace: demo-app
42+
spec:
43+
domainName: my.domain.com
44+
options:
45+
certificateTransparencyLoggingPreference: ENABLED
46+
exportTo:
47+
namespace: demo-app
48+
name: exported-cert-secret
49+
key: tls.crt
50+
...
51+
```
52+
1153
## Contributing
1254

1355
We welcome community contributions and pull requests.
Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
ack_generate_info:
2-
build_date: "2025-11-29T03:39:17Z"
3-
build_hash: 23c7074fa310ad1ccb38946775397c203b49f024
4-
go_version: go1.25.4
5-
version: v0.56.0
6-
api_directory_checksum: 3e7a69c0415ed45a0a26d12bd1498f965d70c69a
2+
build_date: "2025-12-01T23:41:16Z"
3+
build_hash: a3d580fb0f446539bbd1f4efa5a759e59c53cbfa
4+
go_version: go1.25.1
5+
version: v0.56.0-1-ga3d580f
6+
api_directory_checksum: 5dc0b682f154f3479809e330d2760ff9575e9bea
77
api_version: v1alpha1
88
aws_sdk_go_version: v1.32.6
99
generator_config_info:
10-
file_checksum: 1489a54e7f1a1b28f8b44e738c239b03b364f74a
10+
file_checksum: 62b614b540cda719ee9142cbc530d180cbf2c52d
1111
original_file_name: generator.yaml
1212
last_modification:
1313
reason: API generation

apis/v1alpha1/certificate.go

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

apis/v1alpha1/generator.yaml

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,22 +17,16 @@ operations:
1717
resources:
1818
Certificate:
1919
hooks:
20+
delta_pre_compare:
21+
template_path: hooks/certificate/delta_pre_compare.go.tpl
2022
sdk_update_pre_build_request:
2123
template_path: hooks/certificate/sdk_update_pre_build_request.go.tpl
24+
sdk_update_post_set_output:
25+
template_path: hooks/certificate/sdk_update_post_set_output.go.tpl
2226
sdk_create_pre_build_request:
2327
template_path: hooks/certificate/sdk_create_pre_build_request.go.tpl
2428
sdk_create_post_build_request:
25-
# NOTE(jaypipes): We only support DNS-based validation, because
26-
# certificate renewal is not really automatable when email verification
27-
# is used.
28-
#
29-
# See discussion here:
30-
# https://docs.aws.amazon.com/acm/latest/userguide/email-validation.html
31-
#
32-
# Unfortunately, because fields in the "ignore" configuration list are
33-
# now deleted from the aws-sdk-go private/model/api.Shape object,
34-
# setting `override_values` above does not work :(
35-
code: input.ValidationMethod = "DNS"
29+
template_path: hooks/certificate/sdk_create_post_build_request.go.tpl
3630
sdk_read_one_pre_set_output:
3731
template_path: hooks/certificate/sdk_read_one_pre_set_output.go.tpl
3832
sdk_file_end:
@@ -53,6 +47,12 @@ resources:
5347
reconcile:
5448
requeue_on_success_seconds: 60
5549
fields:
50+
ExportTo:
51+
type: "bytes"
52+
is_immutable: true
53+
is_secret: true
54+
compare:
55+
is_ignored: true
5656
DomainName:
5757
is_primary_key: false
5858
is_required: false

apis/v1alpha1/zz_generated.deepcopy.go

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/crd/bases/acm.services.k8s.aws_certificates.yaml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,29 @@ spec:
159159
x-kubernetes-validations:
160160
- message: Value is immutable once set
161161
rule: self == oldSelf
162+
exportTo:
163+
description: |-
164+
SecretKeyReference combines a k8s corev1.SecretReference with a
165+
specific key within the referred-to Secret
166+
properties:
167+
key:
168+
description: Key is the key within the secret
169+
type: string
170+
name:
171+
description: name is unique within a namespace to reference a
172+
secret resource.
173+
type: string
174+
namespace:
175+
description: namespace defines the space within which the secret
176+
name must be unique.
177+
type: string
178+
required:
179+
- key
180+
type: object
181+
x-kubernetes-map-type: atomic
182+
x-kubernetes-validations:
183+
- message: Value is immutable once set
184+
rule: self == oldSelf
162185
keyAlgorithm:
163186
description: |-
164187
Specifies the algorithm of the public and private key pair that your certificate

config/iam/recommended-inline-policy

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
"Version": "2012-10-17",
33
"Statement": [
44
{
5+
"Sid": "ACMPublicCertificatePermissions",
56
"Effect": "Allow",
67
"Action": [
78
"acm:DescribeCertificate",
@@ -11,7 +12,18 @@
1112
"acm:DeleteCertificate",
1213
"acm:AddTagsToCertificate",
1314
"acm:RemoveTagsFromCertificate",
14-
"acm:ListTagsForCertificate"
15+
"acm:ListTagsForCertificate",
16+
"acm:ExportCertificate"
17+
],
18+
"Resource": "*"
19+
},
20+
{
21+
"Sid": "ACMPrivateCertificatePermissions",
22+
"Effect": "Allow",
23+
"Action": [
24+
"acm-pca:IssueCertificate",
25+
"acm-pca:GetCertificate",
26+
"acm-pca:ListPermissions"
1527
],
1628
"Resource": "*"
1729
}

generator.yaml

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,22 +17,16 @@ operations:
1717
resources:
1818
Certificate:
1919
hooks:
20+
delta_pre_compare:
21+
template_path: hooks/certificate/delta_pre_compare.go.tpl
2022
sdk_update_pre_build_request:
2123
template_path: hooks/certificate/sdk_update_pre_build_request.go.tpl
24+
sdk_update_post_set_output:
25+
template_path: hooks/certificate/sdk_update_post_set_output.go.tpl
2226
sdk_create_pre_build_request:
2327
template_path: hooks/certificate/sdk_create_pre_build_request.go.tpl
2428
sdk_create_post_build_request:
25-
# NOTE(jaypipes): We only support DNS-based validation, because
26-
# certificate renewal is not really automatable when email verification
27-
# is used.
28-
#
29-
# See discussion here:
30-
# https://docs.aws.amazon.com/acm/latest/userguide/email-validation.html
31-
#
32-
# Unfortunately, because fields in the "ignore" configuration list are
33-
# now deleted from the aws-sdk-go private/model/api.Shape object,
34-
# setting `override_values` above does not work :(
35-
code: input.ValidationMethod = "DNS"
29+
template_path: hooks/certificate/sdk_create_post_build_request.go.tpl
3630
sdk_read_one_pre_set_output:
3731
template_path: hooks/certificate/sdk_read_one_pre_set_output.go.tpl
3832
sdk_file_end:
@@ -53,6 +47,12 @@ resources:
5347
reconcile:
5448
requeue_on_success_seconds: 60
5549
fields:
50+
ExportTo:
51+
type: "bytes"
52+
is_immutable: true
53+
is_secret: true
54+
compare:
55+
is_ignored: true
5656
DomainName:
5757
is_primary_key: false
5858
is_required: false

go.mod

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@ require (
88
github.com/aws-controllers-k8s/acmpca-controller v0.0.17
99
github.com/aws-controllers-k8s/runtime v0.56.0
1010
github.com/aws/aws-sdk-go v1.49.6
11-
github.com/aws/aws-sdk-go-v2 v1.34.0
12-
github.com/aws/aws-sdk-go-v2/service/acm v1.30.14
13-
github.com/aws/smithy-go v1.22.2
11+
github.com/aws/aws-sdk-go-v2 v1.39.2
12+
github.com/aws/aws-sdk-go-v2/service/acm v1.33.0
13+
github.com/aws/smithy-go v1.23.0
1414
github.com/go-logr/logr v1.4.2
1515
github.com/spf13/pflag v1.0.5
16+
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78
1617
k8s.io/api v0.32.1
1718
k8s.io/apimachinery v0.32.1
1819
k8s.io/client-go v0.32.1
@@ -23,11 +24,11 @@ require (
2324
github.com/aws/aws-sdk-go-v2/config v1.28.6 // indirect
2425
github.com/aws/aws-sdk-go-v2/credentials v1.17.47 // indirect
2526
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.21 // indirect
26-
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.29 // indirect
27-
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.29 // indirect
27+
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.9 // indirect
28+
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.9 // indirect
2829
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect
29-
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1 // indirect
30-
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.6 // indirect
30+
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.1 // indirect
31+
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.9 // indirect
3132
github.com/aws/aws-sdk-go-v2/service/sso v1.24.7 // indirect
3233
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.6 // indirect
3334
github.com/aws/aws-sdk-go-v2/service/sts v1.33.2 // indirect
@@ -53,7 +54,6 @@ require (
5354
github.com/itchyny/gojq v0.12.6 // indirect
5455
github.com/itchyny/timefmt-go v0.1.3 // indirect
5556
github.com/jaypipes/envutil v1.0.0 // indirect
56-
github.com/jmespath/go-jmespath v0.4.0 // indirect
5757
github.com/josharian/intern v1.0.0 // indirect
5858
github.com/json-iterator/go v1.1.12 // indirect
5959
github.com/mailru/easyjson v0.7.7 // indirect
@@ -69,6 +69,7 @@ require (
6969
github.com/x448/float16 v0.8.4 // indirect
7070
go.uber.org/multierr v1.11.0 // indirect
7171
go.uber.org/zap v1.27.0 // indirect
72+
golang.org/x/crypto v0.36.0 // indirect
7273
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
7374
golang.org/x/net v0.38.0 // indirect
7475
golang.org/x/oauth2 v0.27.0 // indirect

0 commit comments

Comments
 (0)