[Feature Request] Import cert from tls.secretName into ACM
Hi, It looks like ACM now permits importing certificates via the API, I'm pretty sure this has been missing previously. Would you be interested in a PR to sync secrets to ACM? I've started working on it under the assumption that you would (didn't see any existing PRs). My current plan is:
- if tls.secretName is set, try and pull a cert, key and certchain from the secret, following format of the secrets used by CertificateManager.
- if all are good, import that cert, if that works, add an annotation to the secret to indicate the ARN
- keep a cache of hashes of some of the cert info (isuer, issued at and issued by), and compare those with the related info from ACM, use those to indicate if an update is needed.
I've started digging around the code a little. It's a bit more heavy going than expected. I'm going to have a poke at it, but it's not going to be quite as quick as expected (may not be able to give it high priority as we can, for now, manage with manually managed ACM certs)
@tcolgate Actually i had an PR for this but closed it. The main reason is ACM only allows u to import like 10 certs per year(total imports instead of active imported cert), which basically makes it a useless feature.
seems they changed it to 1000 now....
Nice! FYI, related issue on the certmanager side https://github.com/jetstack/cert-manager/issues/2302
adding some labels to make this more discoverable to others -the idea sounds good also, here are the docs I could find regarding the limit of 1000 https://docs.aws.amazon.com/acm/latest/userguide/acm-limits.html
/kind feature /priority important-longterm
A lot of the AWS limits can be raised with service requests, though I've not looked at cert limits I must admit.
@M00nF1sh that looks very promising.
@M00nF1sh can you maybe pick up that closed PR? Would be awesome to just mention a list of secrets in an ingress annotation so that they get synced with ACM, and their ARNs added to the alb.ingress.kubernetes.io/certificate-arn list.
Issues go stale after 90d of inactivity.
Mark the issue as fresh with /remove-lifecycle stale.
Stale issues rot after an additional 30d of inactivity and eventually close.
If this issue is safe to close now please do so with /close.
Send feedback to sig-testing, kubernetes/test-infra and/or fejta. /lifecycle stale
/remove-lifecycle stale
Issues go stale after 90d of inactivity.
Mark the issue as fresh with /remove-lifecycle stale.
Stale issues rot after an additional 30d of inactivity and eventually close.
If this issue is safe to close now please do so with /close.
Send feedback to sig-testing, kubernetes/test-infra and/or fejta. /lifecycle stale
Stale issues rot after 30d of inactivity.
Mark the issue as fresh with /remove-lifecycle rotten.
Rotten issues close after an additional 30d of inactivity.
If this issue is safe to close now please do so with /close.
Send feedback to sig-testing, kubernetes/test-infra and/or fejta. /lifecycle rotten
/remove-lifecycle rotten /remove-lifecycle stale
Any updates on using cert-manager let's encrypt certs + alb + eks?
@M00nF1sh any work on this? Looking for the same here... Any progress with lestencrypt + cert-manager
@marcellodesales I'll put this into our backlog, we should be able to work on this post reinvent.
Sharing my not very elegant but working hack for Cert-Manager Let's Encrypt certs + ALB + EKS using a combination of kubectl & aws cli:
- Use the following cluster issuer to get the certificate into the k8s secret: ClusterIssuer.yml:
kind: ClusterIssuer
apiVersion: cert-manager.io/v1
metadata:
name: prod-clusterissuer
spec:
acme:
privateKeySecretRef:
name: prod-clusterissuer
server: 'https://acme-v02.api.letsencrypt.org/directory'
solvers:
- http01:
ingress:
class: alb
ingressTemplate:
metadata:
annotations:
alb.ingress.kubernetes.io/scheme: "internet-facing"
alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}]'
alb.ingress.kubernetes.io/group.name: "group1"
- Deploy the app using Helm: app-helm-values.yml (only relevant part):
ingress:
enabled: true
annotations:
kubernetes.io/ingress.class: "alb"
alb.ingress.kubernetes.io/scheme: "internet-facing"
alb.ingress.kubernetes.io/listen-ports : '[{"HTTP": 80}, {"HTTPS": 443}]'
alb.ingress.kubernetes.io/group.name: "group1"
kubernetes.io/tls-acme: "true"
alb.ingress.kubernetes.io/certificate-arn: ""
hosts:
- host: $HOST
paths:
path: /
tls:
- secretName: $HOST-tls
hosts:
- $HOST
- Wait for the certificate to be created in the K8s secret by cert-manager & then import it into the ACM using aws cli:
kubectl get secret $HOST-tls -o yaml | yq r - data.[tls.crt] | base64 -d | sed -e '/-----END CERTIFICATE-----/q' > $CI_PROJECT_DIR/Certificate.pem
kubectl get secret $HOST-tls -o yaml | yq r - data.[tls.crt] | base64 -d > $CI_PROJECT_DIR/CertificateChain.pem
kubectl get secret $HOST-tls -o yaml | yq r - data.[tls.key] | base64 -d > $CI_PROJECT_DIR/PrivateKey.pem
aws acm import-certificate \
--certificate fileb://Certificate.pem \
--certificate-chain fileb://CertificateChain.pem \
--private-key fileb://PrivateKey.pem
export CERTIFICATE_ARN=$(aws acm list-certificates --query CertificateSummaryList[].[CertificateArn,DomainName] --output text | grep "$HOST" | cut -f1 | head -n 1)
kubectl annotate --overwrite ingress app alb.ingress.kubernetes.io/certificate-arn=$CERTIFICATE_ARN
In my case head -n 1 always shows the certificate which is in use by ALB & to verify it I'm using the following query expecting a non empty output:
aws acm describe-certificate --certificate-arn $(aws acm list-certificates --query CertificateSummaryList[].[CertificateArn,DomainName] --output text | grep "$HOST" | cut -f1 | head -n 1) --query Certificate.InUseBy --output text
You can use it without head -n 1 & loop over the output ARNs to find which certificate ARN is in use & use exactly it (in case the behavior of the aws cli list-certificates output changes.
@vainkop That's a great start... thank you! As a next step... Independently of the ClusterIssuer type used (DNS0, or HTTP01), we could have a container listening to events on the creation of the certs...
Questions
- Did that work leaving the
certificate-arnas empty? I hadn't check using that... - Didn't you need to refer to the cluster issuer?
prod-clusterissuer?
Next steps maybe?
- Require the user to create an IAM Role with permissions to the ACM APIs
- Create an AWS CLI container that listens to the events of the Cert creation
- It should have the OIDC role created for the ServiceAccount for the container
- Implement the CRD that listens to the events of certs rotation
- so that we can renew the cert...
I wish I had time to tacle that, but I hope to see the work from @M00nF1sh if he's closer to get done...
Questions
- Did that work leaving the
certificate-arnas empty? I hadn't check using that... Yes it works or you can create the ingress without this annotation & set the port to f.e. 80 only just to get the traffic into the acme solver for the certificate to be created in the K8s secret & then import the certificate into ACM & annotate the ingress with the certificate arn & add the 443 port (that's how I did it)kubectl annotate --overwrite ingress app alb.ingress.kubernetes.io/listen-ports='[{"HTTP":80}, {"HTTPS":443}]'
- Didn't you need to refer to the cluster issuer?
prod-clusterissuer?
No I don't need to refer to the cluster issuer as I've used the following options to install the cert-manager:
helm upgrade -i cert-manager jetstack/cert-manager \
--set ingressShim.defaultIssuerName=prod-clusterissuer \
--set ingressShim.defaultIssuerKind=ClusterIssuer \
--set ingressShim.defaultIssuerGroup=cert-manager.io \
...
Next steps maybe?
- Require the user to create an IAM Role with permissions to the ACM APIs
Currently It works like that for me as I'm using the CI with IAM credentials enough to perform the necessary operations.
- Create an AWS CLI container that listens to the events of the Cert creation
Here's what I use to wait for the certificate (I know it's a little ugly, but again: it's working)
while ! kubectl get secret $HOST-tls; do echo "The certificate is not ready yet. Sleeping 10 seconds..." && sleep 10; done
It's all automated in one pipeline.
- Implement the CRD that listens to the events of certs rotation
- so that we can renew the cert...
I can see how it can be automated easily, f.e. by creating a k8s job which checks the certificate expiration & then triggers the pipeline job to reimport the certificate like I've written above.
I really hope someone implements it in the cert-manager itself without all this bashism! :)
& while that works I'm hitting the aws api & acm limits :(
An error occurred (LimitExceededException) when calling the ImportCertificate operation (reached max retries: 2): You have imported the maximum number of 20 certificates in the last year.
I asked them for an increase and was granted the maximum per year of 5000 ;)
Also, I have created a similar solution that I abandoned because of that same limitation. I just decided to avoid ALBs until something would change. You can find that part in something much bigger that we open sourced last week under the radar. Please don't expect all documentation to match the developer experience just yet. Please look at redkubes.github.io/otomi/ and from there check out the parts. You should find it in the tasks repo.
Would love to get feedback!
I asked them for an increase and was granted the maximum per year of 5000 ;)
Also, I have created a similar solution that I abandoned because of that same limitation. I just decided to avoid ALBs until something would change. You can find that part in something much bigger that we open sourced last week under the radar. Please don't expect all documentation to match the developer experience just yet. Please look at redkubes.github.io/otomi/ and from there check out the parts. You should find it in the tasks repo.
Would love to get feedback!
Yes, it's not a problem to get an increase.
The other limitation I'm concerned with is the absense of "normal" rewrites on the ALB side. The solution using "actions" doesn't look clean to me. Issue: https://github.com/kubernetes-sigs/aws-load-balancer-controller/issues/835
The link on the page is broken? https://redkubes.github.io/otomi/docs/about-otomi https://redkubes.com/otomi-tasks/
Holy kubes! You seem to have found a page that no longer exists...
We are very sorry for this inconvenience.
I've found the relevant code in the repo (https://github.com/redkubes/otomi-tasks/blob/master/src/tasks/otomi/certs-aws.ts) & it looks like you're basically doing the same thing as me but in typescript & async-like :)
I'm actually also thinking about abandoning ALBs because of all that.
Is using NLB + nginx/haproxy/... ingress controller in daemonset/... the most common practice on AWS/EKS or there's something better & more "AWS/EKS native"? Of course the main idea for using ALB was integration with other AWS services like WAF & etc
The link on the page is broken?
Thanks for the feedback, just fixed it.
I'm actually also thinking about abandoning ALBs because of all that.
Is using NLB + nginx/haproxy/... ingress controller in daemonset/... the most common practice on AWS/EKS or there's something better & more "AWS/EKS native"? Of course the main idea for using ALB was integration with other AWS services like WAF & etc
We automated all of it, but it feels wrong, like you said. If somebody wants to contribute/maintain our so called "Task" that would be awesome. We don't give it prio now (also because NL is much more Azure oriented, unfortunately).
Issues go stale after 90d of inactivity.
Mark the issue as fresh with /remove-lifecycle stale.
Stale issues rot after an additional 30d of inactivity and eventually close.
If this issue is safe to close now please do so with /close.
Send feedback to sig-contributor-experience at kubernetes/community. /lifecycle stale
/remove-lifecycle stale
@M00nF1sh Last update was
I'll put this into our backlog, we should be able to work on this post reinvent.
Any chance there's an update on this?
Without this we're going to have to go back to ingress-nginx.
Stale issues rot after 30d of inactivity.
Mark the issue as fresh with /remove-lifecycle rotten.
Rotten issues close after an additional 30d of inactivity.
If this issue is safe to close now please do so with /close.
Send feedback to sig-contributor-experience at kubernetes/community. /lifecycle rotten
I still very much would like this feature. I'm currently using a homegrown solution to import issued certificates via cert-manager, into ACM for use in the Ingress.
An officially supported option would be very welcome 👍
ACM still has the total number of certificates that can be imported per year. We will follow up with the ACM team on the limitations.
I've unsubscribed from this but it still shows up on my open issues list ('cos I opened it I guess). Ideally, could someone that's interested, and maybe working on it, open a new issue?