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 sslPolicy for NLB to change listener's security policy #9666

Merged

Conversation

FrankYang0529
Copy link
Contributor

@FrankYang0529 FrankYang0529 commented Aug 2, 2020

closes #9633

@k8s-ci-robot k8s-ci-robot added do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. labels Aug 2, 2020
@k8s-ci-robot
Copy link
Contributor

Hi @FrankYang0529. Thanks for your PR.

I'm waiting for a kubernetes member to verify that this patch is reasonable to test. If it is, they should reply with /ok-to-test on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work. Regular contributors should join the org to skip this step.

Once the patch is verified, the new status will be reflected by the ok-to-test label.

I understand the commands that are listed here.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

@k8s-ci-robot k8s-ci-robot added needs-ok-to-test Indicates a PR that requires an org member to verify it is safe to test. area/api labels Aug 2, 2020
@k8s-ci-robot k8s-ci-robot added area/provider/aws Issues or PRs related to aws provider size/M Denotes a PR that changes 30-99 lines, ignoring generated files. labels Aug 2, 2020
@FrankYang0529 FrankYang0529 changed the title WIP: add PolicyNames for ELB to change listener's security policy Add PolicyNames for ELB to change listener's security policy Aug 3, 2020
@k8s-ci-robot k8s-ci-robot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Aug 3, 2020
@rifelpet
Copy link
Member

rifelpet commented Aug 3, 2020

/ok-to-test

Thanks for adding this! I haven't looked at the ELB API behavior closely but we should make sure that when someone removes listenerPolicies from their ClusterSpec that the API ELB is updated to use AWS' default listener policy. We'll also want to add terraform and cloudformation support but that can happen in followup PRs.

@k8s-ci-robot k8s-ci-robot added ok-to-test Indicates a non-member PR verified by an org member that is safe to test. and removed needs-ok-to-test Indicates a PR that requires an org member to verify it is safe to test. labels Aug 3, 2020
@FrankYang0529
Copy link
Contributor Author

@rifelpet Thanks for reviewing! I have two questions about generating terraform and cloudformation.

  • For terraform, it uses another resource name for listener's policy. Is it correct to only add RenderTerraform and TerraformLink functions for LoadBalancerListener, so we can have corresponding terraform resource?
  • For cloudformation, I am not sure why we only generate TCP listeners? Cloudformation has PolicyNames field in listener. So if we distinguish whether load balancer port is 443 in RenderCloudformation, we can add corresponding policy names.

@rifelpet
Copy link
Member

rifelpet commented Aug 4, 2020

  • We should be able to render two terraform resources from one RenderTerraform function, heres an example. You'll just need an additional terraform type with all the fields necessary for the additional resource type.

  • Regarding cloudformation, my guess is that Kops' ACM Certificate support wasnt extended to include cloudformation, so we may be hardcoding the TCP listener there. If that's the case then it would be good to support both ACM certs and this new security policy in cloudformation but again, this can be a followup PR.

Also we'll want to add this to an integration test which will test both the terraform and cloudformation outputs. Add the new field to the ClusterSpec in the two in-*.yaml files here, and run ./hack/update-expected.sh and you should see the terraform and CF files in the same directory be updated to match.

@olemarkus
Copy link
Member

Small one from me: Add a line about this in the cluster spec docs (docs/cluster_spec.md)

@k8s-ci-robot k8s-ci-robot added area/documentation size/L Denotes a PR that changes 100-499 lines, ignoring generated files. and removed size/M Denotes a PR that changes 30-99 lines, ignoring generated files. labels Aug 11, 2020
@FrankYang0529 FrankYang0529 force-pushed the feat/aws-elb-listener-policy branch 2 times, most recently from 9cf770e to 89d5d9f Compare August 11, 2020 15:22
@FrankYang0529
Copy link
Contributor Author

Updated it. Thank you!

@olemarkus
Copy link
Member

/lgtm

@k8s-ci-robot k8s-ci-robot added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Aug 16, 2020
Copy link
Member

@rifelpet rifelpet left a comment

Choose a reason for hiding this comment

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

So I tested this out and ran into some trouble. I tried to add this policy to my API ELB: ELBSecurityPolicy-TLS-1-2-2017-01 but received this error during update cluster --yes:

W0826 15:49:52.508545   63215 executor.go:128] error running task "LoadBalancer/api.foo.k8s.local" (8m0s remaining to succeed): error updating load balancer listener's security policy: PolicyNotFound: There is no policy with name ELBSecurityPolicy-TLS-1-2-2017-01 for load balancer api-ho-dev-a-us-west-2-k8-a656uf
        status code: 400, request id: 0814b82c-2e84-4f08-a67e-b8f0cd5fd979

even though that is a valid policy name according to aws elb describe-load-balancer-policies.

Reading these docs it seems I would need to "create" the policy for the load balancer from the predefined policies, and then I can assign it to the listener.

aws elb create-load-balancer-policy --load-balancer-name my-loadbalancer
--policy-name my-SSLNegotiation-policy  --policy-type-name SSLNegotiationPolicyType
--policy-attributes AttributeName=Reference-Security-Policy,AttributeValue=ELBSecurityPolicy-2016-08

I'm wondering if Kops should try to reconcile this as well, creating the load-balancer-policy if it does not already exist, based on the API Field being used as the Rerence-Security-Policy. Once it is ensured to exist for the API ELB then Kops can SetLoadBalancerPoliciesOfListener. Thoughts?

I also think we will want to add API validation that makes sure this field is only set if the sslCertificate field is also set. We could add the validation here:

if c.Spec.API != nil {
if c.Spec.API.LoadBalancer != nil {
allErrs = append(allErrs, awsValidateAdditionalSecurityGroups(field.NewPath("spec", "api", "loadBalancer", "additionalSecurityGroups"), c.Spec.API.LoadBalancer.AdditionalSecurityGroups)...)
}
}

and I think field.Forbidden() might be the most appropriate validation error for this.

@@ -529,6 +536,24 @@ func (_ *LoadBalancer) RenderAWS(t *awsup.AWSAPITarget, a, e, changes *LoadBalan
return fmt.Errorf("Unable to find newly created ELB %q", loadBalancerName)
}
e.HostedZoneId = lb.CanonicalHostedZoneNameID

// Set ELB listener's Security Policy
if l, ok := e.Listeners["443"]; ok && len(l.PolicyNames) != 0 {
Copy link
Member

Choose a reason for hiding this comment

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

Rather than looking for the listener on port 443 perhaps it would be more flexible to perform this logic on any listener that has a Protocol of SSL?

Copy link
Contributor Author

@FrankYang0529 FrankYang0529 Sep 6, 2020

Choose a reason for hiding this comment

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

We only apply security policies when specifying an ACM certificate. However, we set the listener on port 443 when the ACM certificate is existent. So I only set security policies for the listener on port 443 here.

if lbSpec.SSLCertificate != "" {
listeners["443"] = &awstasks.LoadBalancerListener{InstancePort: 443, SSLCertificateID: lbSpec.SSLCertificate}
}

@FrankYang0529
Copy link
Contributor Author

Sounds good! Let's wait for #9011 to land and only add support for setting policies on NLBs.

@rifelpet
Copy link
Member

rifelpet commented Nov 2, 2020

@FrankYang0529 The NLB PR has been merged, are you still willing to update this to support NLB Listener SSLPolicies?

@k8s-ci-robot k8s-ci-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Nov 2, 2020
@FrankYang0529
Copy link
Contributor Author

@rifelpet Yes, I will update it this week.

@k8s-ci-robot k8s-ci-robot added size/M Denotes a PR that changes 30-99 lines, ignoring generated files. and removed needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. size/L Denotes a PR that changes 100-499 lines, ignoring generated files. labels Nov 10, 2020
@FrankYang0529
Copy link
Contributor Author

@rifelpet , I have updated it. We can support NLB Listener SSL Policy now.

Copy link
Member

@rifelpet rifelpet left a comment

Choose a reason for hiding this comment

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

This is much simpler now that it supports NLBs rather than classic load balancers :) nice work!

We'll want to add terraform and cloudformation support for this too. It should just be a matter of adding the new field here and setting its value below:

type terraformNetworkLoadBalancerListener struct {
LoadBalancer *terraform.Literal `json:"load_balancer_arn" cty:"load_balancer_arn"`
Port int64 `json:"port" cty:"port"`
Protocol string `json:"protocol" cty:"protocol"`
CertificateARN *string `json:"certificate_arn,omitempty" cty:"certificate_arn"`
DefaultAction []terraformNetworkLoadBalancerListenerAction `json:"default_action" cty:"default_action"`
}

and cloudformation has its own struct later in the file too. (docs for terraform and cloudformation)

If you want I can do that in a followup PR.

pkg/apis/kops/cluster.go Outdated Show resolved Hide resolved
pkg/apis/kops/validation/aws.go Outdated Show resolved Hide resolved
pkg/model/awsmodel/api_loadbalancer.go Show resolved Hide resolved
@FrankYang0529
Copy link
Contributor Author

@rifelpet Thanks for reviewing. I updated the code and added SSLPolicy in terraform and cloudformation.

@rifelpet rifelpet changed the title Add PolicyNames for ELB to change listener's security policy Add sslPolicy for NLB to change listener's security policy Nov 13, 2020
@rifelpet
Copy link
Member

rifelpet commented Nov 13, 2020

looks good, one last suggestion:

Can you add an example sslPolicyto the two tests/integration/update_cluster/complex/in-*.yaml files? Then run ./hack/update-expected.sh and the kubernetes.tf and cloudformation.json in the same directory should get updated. commit all 4 changes here.

@FrankYang0529
Copy link
Contributor Author

@rifelpet, I have added sslPolicy in two yaml files. However, I am not sure why I can't run tests successfully for k8s.io/kops/cmd/kops. Could you show me how to fix the test error? Thank you.

@rifelpet
Copy link
Member

rifelpet commented Nov 18, 2020

The verify-cloudformation failure is unrelated and was fixed by #10256. This PR's next invocation of that job should pass.

The TestLifecycleComplex failures are because the network load balancer task isn't recognizing the new field when describing the existing listeners in AWS. Reading the test failure output:

    lifecycle_integration_test.go:218: Target had changes after executing: Will modify resources:
          NetworkLoadBalancer/api-complex-example-com
          	Listeners           	 [{"Port":443,"TargetGroupName":"tls-complex-example-com-5nursn","SSLCertificateID":"arn:aws:acm:us-test-1:000000000000:certificate/123456789012-1234-1234-1234-12345678","SSLPolicy":""}, {"Port":8443,"TargetGroupName":"tcp-complex-example-com-vpjolq","SSLCertificateID":"","SSLPolicy":""}] -> [{"Port":443,"TargetGroupName":"tls-complex-example-com-5nursn","SSLCertificateID":"arn:aws:acm:us-test-1:000000000000:certificate/123456789012-1234-1234-1234-12345678","SSLPolicy":"ELBSecurityPolicy-2016-08"}, {"Port":8443,"TargetGroupName":"tcp-complex-example-com-vpjolq","SSLCertificateID":"","SSLPolicy":""}] 

This can be interpreted as "after applying the changes, Kops' interpretation of the NLB listener state doesn't match what it had just sent to AWS. Therefore there's either a bug in the Find() or RenderAWS() logic. In this case we can see the "actual" state read from AWS (the values before the ->) doesn't have the SSLPolicy set on the first listener, even though we included it in the CreateListener call. The SslPolicy does exist in the DescribeListener response, we just aren't doing anything with it.

Fixing it should just be a matter of setting the actualListener's value here, like we do with Port:

response, err := cloud.ELBV2().DescribeListeners(request)
if err != nil {
return nil, fmt.Errorf("error querying for NLB listeners :%v", err)
}
actual.Listeners = []*NetworkLoadBalancerListener{}
actual.TargetGroups = []*TargetGroup{}
for _, l := range response.Listeners {
actualListener := &NetworkLoadBalancerListener{}
actualListener.Port = int(aws.Int64Value(l.Port))
if len(l.Certificates) != 0 {
actualListener.SSLCertificateID = aws.StringValue(l.Certificates[0].CertificateArn) // What if there is more then one certificate, can we just grab the default certificate? we don't set it as default, we only set the one.
}

@FrankYang0529
Copy link
Contributor Author

@rifelpet Thank you for your elaboration. I know how it works now! Also, I have updated the code and I can run tests successfully.

@rifelpet
Copy link
Member

looks great, thanks for sticking with this!

/lgtm
/approve

@k8s-ci-robot k8s-ci-robot added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Nov 19, 2020
@k8s-ci-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: FrankYang0529, rifelpet

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@k8s-ci-robot k8s-ci-robot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Nov 19, 2020
@k8s-ci-robot k8s-ci-robot merged commit 27f9114 into kubernetes:master Nov 19, 2020
@k8s-ci-robot k8s-ci-robot added this to the v1.20 milestone Nov 19, 2020
@FrankYang0529 FrankYang0529 deleted the feat/aws-elb-listener-policy branch November 19, 2020 14:35
k8s-ci-robot added a commit that referenced this pull request Nov 21, 2020
…9666-upstream-release-1.19

Automated cherry pick of #10256: Fix cloudformation lint job #9666: feat(aws): add PolicyNames for ELB to change listener's
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved Indicates a PR has been approved by an approver from all required OWNERS files. area/api area/documentation area/provider/aws Issues or PRs related to aws provider cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. lgtm "Looks good to me", indicates that a PR is ready to be merged. ok-to-test Indicates a non-member PR verified by an org member that is safe to test. size/M Denotes a PR that changes 30-99 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Able to change api aws elb policy with annotation
4 participants