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

Proxy Protocol support for AWS ELB #516

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

stuszynski
Copy link

This PR adds a new option for load_balancer resource to enable a Proxy Protocol Header on desired ports.

It requires a proxy_protocol item in load_balancer_options configuration hash. For eg.

proxy_protocol:  {
  instance_ports: [80, 443]
}

This will create an #{actual_elb.name}-proxy-protocol-policy policy and attach it to a backend port 80, and 443. It looks only for existing listeners with instance_port and it removes backend server policy settings on any other ports if not listed.

What do you think of it?

Adds support for [Proxy Protocol Header](http://docs.aws.amazon.com/elasticloadbalancing/latest/classic/enable-proxy-protocol.html#proxy-protocol) support for `load_balancer` resource.

Add `proxy_protocol` element to `load_balancer_options` configuration hash. For eg.

    proxy_protocol:  {
      instance_ports: [80, 443]
    }

This will create and add a policy `#{actual_elb.name}-proxy-protocol-policy` to selected Load Balancer and attach it to port 80, and 443. It looks only for existing listners with `instance_port` and removing backend server policy settings if necessary.

Signed-off-by: Stanisław Tuszyński <[email protected]>
@tyler-ball
Copy link
Contributor

tyler-ball commented Mar 2, 2017

Hey @stuszynski! Thanks for getting this PR setup. I have a few pieces of feedback but I think we can work on getting this merged.

First, we definitely want to get tests added for this. Have you ever tried to run the tests locally? You can run the load balancer tests by (in the repo) running bundle install && AWS_TEST_DRIVER=aws::us-east-1 bundle exec rspec spec/integration/load_balancer_spec.rb. This will use your default credentials and spin up things in the us-east-1 availability zone. This can be changed to any zone you want.

To be clear: do not do this any place it can corrupt actual data! I have a test account I use and I supply the profile name for that tester account with AWS_TEST_DRIVER=aws:tester:us-east-1. The tests should be isolated and idempotent (clean up after themselves) but nothing is guaranteed with integration tests. I'm going to try setting up some tests that I can help contribute in a second.

My other point of feedback is that we need this new attribute to be idempotent - it needs to be deleteable. Can you add logic so that if a recipe says proxy_protocol: false then the policy is deleted? I think the logic would look something like

if proxy_protocol == false
  # do stuff to delete the "#{actual_elb.name}-proxy-protocol-policy" object
elsif proxy_protocol
  # existing create logic
end

That isn't a fully idempotent attribute (it would be if it switched the policy to the correct ports like the sticky_sessions attribute does) but I think this would be a good first pass.

With this logic and test coverage I think we can definitely get this merged. Thanks!

@tyler-ball
Copy link
Contributor

From 3b80a04c5992b59c568b5a42550e6702a518d566 Mon Sep 17 00:00:00 2001
From: tyler-ball <[email protected]>
Date: Thu, 2 Mar 2017 12:05:53 -0600
Subject: [PATCH] WIP: tests

---
 spec/integration/load_balancer_spec.rb | 34 +++++++++++++++++++++++++++++++---
 1 file changed, 31 insertions(+), 3 deletions(-)

diff --git a/spec/integration/load_balancer_spec.rb b/spec/integration/load_balancer_spec.rb
index dba8dbf..52fc556 100644
--- a/spec/integration/load_balancer_spec.rb
+++ b/spec/integration/load_balancer_spec.rb
@@ -61,6 +61,9 @@ describe Chef::Resource::LoadBalancer do
                 cookie_name: 'test-cookie-name',
                 ports: [80, 443]
               },
+              proxy_protocol:  {
+                instance_ports: [80, 443]
+              },
               scheme: "internal",
               attributes: {
                 cross_zone_load_balancing: {
@@ -141,18 +144,36 @@ describe Chef::Resource::LoadBalancer do
           {
             policy_attribute_descriptions: [
               {attribute_value: "test-cookie-name", attribute_name: "CookieName"}
-          ],
+            ],
             policy_type_name: "AppCookieStickinessPolicyType",
             policy_name: "test-load-balancer-sticky-session-policy"
           }
         )
 
-        listener_descriptions = driver.elb_client.describe_load_balancers(load_balancer_names: ['test-load-balancer'])[:load_balancer_descriptions][0][:listener_descriptions]
+        proxy_policy = driver.elb_client.describe_load_balancer_policies(load_balancer_name: 'test-load-balancer')[:policy_descriptions].detect { |pd| pd[:policy_type_name] == 'ProxyProtocolPolicyType' }.to_h
+        expect(proxy_policy).to eq(
+          {
+            policy_name: "test-load-balancer-proxy-protocol-policy",
+            policy_type_name: "ProxyProtocolPolicyType",
+            policy_attribute_descriptions: [
+              {attribute_name: "ProxyProtocol", attribute_value: "true"}
+            ]
+          }
+        )
+
+        lb_descriptions = driver.elb_client.describe_load_balancers(load_balancer_names: ['test-load-balancer'])[:load_balancer_descriptions][0]
+        listener_descriptions = lb_descriptions[:listener_descriptions]
         expect(listener_descriptions.size).to eql(2)
         http_listener = listener_descriptions.detect { |ld| ld[:listener][:load_balancer_port] == 80 }
         https_listener = listener_descriptions.detect { |ld| ld[:listener][:load_balancer_port] == 443 }
         expect(http_listener[:policy_names]).to include('test-load-balancer-sticky-session-policy')
         expect(https_listener[:policy_names]).to include('test-load-balancer-sticky-session-policy')
+
+        backend_server_descriptions = lb_descriptions[:backend_server_descriptions]
+        expect(backend_server_descriptions.map &:to_h).to eq([
+          {:instance_port=>80, :policy_names=>["test-load-balancer-proxy-protocol-policy"]},
+          {:instance_port=>443, :policy_names=>["test-load-balancer-proxy-protocol-policy"]}
+        ])
       end
 
       context 'with an existing load balancer' do
@@ -199,6 +220,9 @@ describe Chef::Resource::LoadBalancer do
               cookie_name: 'test-cookie-name',
               ports: [80]
             },
+            proxy_protocol:  {
+              instance_ports: [80, 443]
+            },
             scheme: "internal",
             attributes: {
               cross_zone_load_balancing: {
@@ -252,6 +276,7 @@ describe Chef::Resource::LoadBalancer do
                   cookie_name: 'test-cookie-name2',
                   ports: [443]
                 },
+                proxy_protocol: false,
                 # scheme is immutable, we cannot update it
                 #scheme: "internet-facing",
                 attributes: {
@@ -333,8 +358,11 @@ describe Chef::Resource::LoadBalancer do
             }
           )
 
+          proxy_policy = driver.elb_client.describe_load_balancer_policies(load_balancer_name: 'test-load-balancer')[:policy_descriptions].detect { |pd| pd[:policy_type_name] == 'ProxyProtocolPolicyType' }
+          expect(proxy_policy).to eq(nil)
+
           listener_descriptions = driver.elb_client.describe_load_balancers(load_balancer_names: ['test-load-balancer'])[:load_balancer_descriptions][0][:listener_descriptions]
-          expect(listener_descriptions.size).to eql(1)
+          expect(listener_descriptions.size).to eql(2)
           https_listener = listener_descriptions.detect { |ld| ld[:listener][:load_balancer_port] == 443 }
           expect(https_listener[:policy_names]).to include('test-load-balancer-sticky-session-policy')
         end
-- 
2.11.1

Here is a patch file that takes a stab at the tests. They are failing right now because it looks like it is only attaching the policy to the first port?

@stuszynski
Copy link
Author

@tyler-ball Hi! Great thanks for a feedback. I'll look into this in my spare time.

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

Successfully merging this pull request may close these issues.

2 participants