Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add sni support #111

Merged
merged 15 commits into from
Feb 19, 2018
Merged

Add sni support #111

merged 15 commits into from
Feb 19, 2018

Conversation

mikkeloscar
Copy link
Collaborator

@mikkeloscar mikkeloscar commented Dec 17, 2017

This adds SNI support by adding up to 25 certificates to a single ALB. If multiple ALBs exist with less than 25 certificates each then it will aggregate the certificates to as few ALBs as possible.

To support multiple certs this also fixes a bunch of other issues:

  • Changes how stacks are updated. Before they were scheduled for update every hour (even if no updates were needed) and now it will check if there are any updates needed and update straight away. Without this change it would have taken 1 hour to add a new certificate to an existing ALB stack.
  • Changes cloudformation template from a yaml template to use the library https://github.com/mweagle/go-cloudformation to generate the template using Go. This is needed because we want to dynamically add certificates to the stack, which is not possible with pure cloudformation.
  • Changes stack naming. Before the name was something like cluster-id-<hash-of-cert-arn>-scheme but since we can now have 25 certs per stack the naming no longer makes sense. Instead it just gets the name cluster-id-<uuid>.

Migration

This PR also takes care to ensure safe migration from stacks created by the <=v0.5.0 version of the controller. The migration works like this:

  1. Find old stacks with only one certificate.
  2. Aggregate certs into one of the stacks (assuming less than 25 certs in total).
  3. Mark old stacks to be deleted with a ttl on the existing cert the stack had defined.
  4. Delete old stacks after the ttl has expired, allowing enough time for e.g. external-dns to move to the new stack.

Each certificate is defined on the stack with a tag ingress:certificate-arn/<cert-arn>=ttl where ttl is a timestamp for when the cert should be removed from the stack. This way it's possible to create multiple stacks in case there are more than 25 certs requested. And it's possible to later merge the stacks back to one when the demand for certs are less than 25 again.

Note: with this approach it's not possible to explicitly get an ALB that is unique per ingress/certificate we could add support for this either through a flag or as an annotation added to ingresses which want to have their own ALB, however this PR is already quite big so I would add these features separately.

Fix #94

@coveralls
Copy link

coveralls commented Dec 17, 2017

Coverage Status

Coverage decreased (-0.8%) to 52.539% when pulling 65fd11b on sni-support into 806f9df on master.

@mikkeloscar mikkeloscar changed the title Add sni support [WIP] Add sni support Dec 17, 2017
aws/adapter.go Outdated
@@ -64,7 +64,7 @@ const (

nameTag = "Name"

certificateARNTag = "ingress:certificate-arn"
certificateARNsTag = "ingress:certificate-arns"
Copy link
Member

@szuecs szuecs Dec 18, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this will break existing installations, please make it upgradeable and set a deprecated comment and log a warning if used

aws/cf.go Outdated
dnsName string
scheme string
targetGroupARN string
CertificateARNs []string
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please do not change visibility here, better add a method, for example: Add(certarns ...string)

aws/cf.go Outdated
CertificateArn string `yaml:"CertificateArn"`
}

// cfTemplate is an opauqe structure for unmarshaling a yaml cloudformation
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

opauqe -> opaque

aws/cf.go Outdated

// injectCertificates injects a list of certificates into the cloudformation
// template.
func injectCertificates(cfTmpl string, certs []string) (string, error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not happy with the solution parsing string, modify object and return string.
This looks more like a hack to me. We should have a type based object that can render to a cloudformation stack.

@@ -138,10 +139,18 @@ func doWork(certsProvider certs.CertificatesProvider, awsAdapter *aws.Adapter, k
return nil
}

func buildManagedModel(certsProvider certs.CertificatesProvider, ingresses []*kubernetes.Ingress, stacks []*aws.Stack) map[string]*managedItem {
model := make(map[string]*managedItem)
func buildManagedModel(certsProvider certs.CertificatesProvider, ingresses []*kubernetes.Ingress, stacks []*aws.Stack) []*managedItem {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the changes in this function look more like we lack of abstraction and power of the abstraction.

@szuecs
Copy link
Member

szuecs commented Dec 18, 2017

👎

@greenboxal
Copy link
Contributor

Is this PR active? This is a super important feature for us as we use ingress for basically everything, and having one ALB per service is too expensive.

If not, I'm interested in finishing it.

@szuecs
Copy link
Member

szuecs commented Jan 15, 2018

@greenboxal I think we have not so much pressure as we provision wildcard certificates and mostly use the same ALB for all ingress already. Feel free to work on that.

@mikkeloscar
Copy link
Collaborator Author

@greenboxal I have some half finished work locally, which I will try to push one of the next days.

@coveralls
Copy link

coveralls commented Jan 16, 2018

Coverage Status

Coverage increased (+1.0%) to 60.804% when pulling c96bb8c on sni-support into 289884b on master.

@mikkeloscar
Copy link
Collaborator Author

I have now updated this with all the changes I had locally. It now uses the github.com/mweagle/go-cloudformation library to generate a CF stack template instead of doing some weird yaml unmarshal/marshaling like it did before.

Note that this currently hasn't been tested and there are at least some issues I'm aware of:

  • Naming of the stacks.
    • Currently we do this with a hash over the certificate, but since this can have 25 certs it no longer makes sense.
  • When aggregating existing stacks into less stacks because of multiple certificates per stack/ALB then we need to do it in a way were the old stacks are kept for a bit during the migration. We have a default of 5 minutes right now (stackTTL).

Both of these things has to be done in a backwardcompatible way such that we can automatically migrate the single cert ALBs to multi cert ALBs without affecting applications behind those ingress ALBs.

@greenboxal If you want to go on from here, you are welcome to do so just let me know, otherwise I will work on this in CW04.

@mikkeloscar mikkeloscar changed the title [WIP] Add sni support Add sni support Feb 18, 2018
@mikkeloscar
Copy link
Collaborator Author

mikkeloscar commented Feb 18, 2018

@szuecs I have now updated the description explaining how it works.

I have tested the following scenarios:

  • Have two existing stacks from the previous version of the controller and switch to the new one.
  • Have a single stack with two certs and run a (custom) controller with a cert/stack limit of 1. This will split the stack in two.
  • Have two stacks with a cert each and run the controller with a cert/stack limit of 25 and see the stacks getting merged into one.
  • Test that all of this doesn't impact clients calling an endpoint behind ingress.

@mikkeloscar
Copy link
Collaborator Author

@greenboxal This should now be done. You are very welcome to give it a try.

Here's an image built from this PR: registry.opensource.zalan.do/teapot/kube-ingress-aws-controller-test:pr-111-15

worker.go Outdated
if err != kubernetes.ErrUpdateNotNeeded {
log.Println(err)
} else {
log.Printf("updated ingress not needed %v with DNS name %q", ing, dnsName)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please switch the error handling and change the message.

if err == kubernetes.ErrUpdateNotNeeded {
    log.Printf("Ingress update not needed %v with DNS name %q", ing, dnsName)
} else {
    log.Printf("Failed to update ingress: %v", err)
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed!

@szuecs
Copy link
Member

szuecs commented Feb 19, 2018

I discussed offline with @mikkeloscar and checked the code with 4 eyes that it will support more than 2 stacks, too. (I dropped my old comment)

Only small refactoring to have it more readable. Thanks!

@szuecs
Copy link
Member

szuecs commented Feb 19, 2018

👍

1 similar comment
@mikkeloscar
Copy link
Collaborator Author

👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

AWS Application Load Balancers Now Support Multiple TLS Certificates (SNI)
4 participants