AWS ELB ProxyProtocol with Node findhit-proxywrap

in #nodejs7 years ago

Only bother reading this if you are trying to pass TCP traffic through your ELB and terminate http and https traffic directly. You might want to do this if your application needs to know the client's IP address instead of the ELB's IP address. There are a number of complicated ways to do this out there, namely using haproxy and nginx. In an effort to keep things simple, it was important that I be able to integrate this into my existing node application without any additional moving parts.

This was harder than it should have been, likely because there are differences in how node handles sockets in https in more current versions. My setup is:

AWS ELB (ProxyProtocol Mode, 80, 443) --> AWS Instance (findhit-proxywrap, 80, 443)

Everything worked fine in http mode, but in https mode, I was only seeing the IP of the ELB, instead of the end client. I found this obscure conversation. Which led my to modify on line in this code sample:

You can see here that I am accounting for http and https requests. For the https requests, you need to include options and reference your certs. The code that solves for the https problem is:

var socket = req.socket._parent || req.socket;

And here is the completed code:

var http = require( 'http' )
var https = require( 'https' )
var proxiedHttp = require( 'findhit-proxywrap' ).proxy( http )
var proxiedHttps = require( 'findhit-proxywrap' ).proxy( https )
var express = require( 'express' )
var app = express()
var fs = require('fs')

var options = {
   key  : fs.readFileSync('cavo.key'),
   cert : fs.readFileSync('cavo.cert')
};

// instead of http.createServer(app)
var srv = proxiedHttp.createServer(app).listen( 80 )
var srv2 = proxiedHttps.createServer(options, app).listen( 443 )

app.get( '/', ( req, res ) => {
    var socket = req.socket._parent || req.socket;
    res.send( 'IP = ' + socket.remoteAddress + ':' + socket.remotePort )

Cloudformation snippit for adding proxyprotocol to your ELB:

    "ELB" : {
      "Type" : "AWS::ElasticLoadBalancing::LoadBalancer",
      "Properties" : {
        "LoadBalancerName":"elb-name",
        "Subnets" : ["subnet-xxxxxxx"],
        "Listeners": [
        {
          "LoadBalancerPort": "443",
          "InstancePort": "443",
          "Protocol": "TCP",
          "InstanceProtocol" : "TCP"
        },
        {
          "LoadBalancerPort": "80",
          "InstancePort": "80",
          "Protocol": "TCP",
          "InstanceProtocol" : "TCP"
        }],
        "HealthCheck": {
          "Target": "TCP:80",
          "HealthyThreshold": "2",
          "UnhealthyThreshold": "2",
          "Interval": "30",
          "Timeout": "5"
        },
        "ConnectionDrainingPolicy": {
          "Enabled" : "true",
          "Timeout" : "60"
        },
        "Policies" : [
          {
            "PolicyName" : "EnableProxyProtocol",
            "PolicyType" : "ProxyProtocolPolicyType",
            "Attributes" : [
              {
              "Name"  : "ProxyProtocol",
              "Value" : "true"
              }
            ],
          "InstancePorts" : ["443","80"]
          }
        ],
        "SecurityGroups" : [
            { "Ref" : "SecurityGroup" }
        ]
      }
    },
    "SecurityGroup" : {
    "Type" : "AWS::EC2::SecurityGroup",
    "Properties" : {
        "GroupDescription" : "Web Server Ports",
        "VpcId" : "vpc-6c673f09",
        "Tags": [
              { "Key": "Name", "Value": "cavo_proxy" },
              { "Key": "gl", "Value": "01-63210-100-75" },
              { "Key": "Affiliate", "Value": "Advent" }
        ],
        "SecurityGroupEgress" : [
        {
              "IpProtocol" : "-1",
              "FromPort" : "-1",
              "ToPort" : "-1",
              "CidrIp" : "0.0.0.0/0"
        }
        ],
        "SecurityGroupIngress" : [
        {
              "IpProtocol" : "tcp",
              "FromPort" : "80",
              "ToPort" : "80",
              "CidrIp" : "0.0.0.0/0"
        },
        {
              "IpProtocol" : "tcp",
              "FromPort" : "443",
              "ToPort" : "443",
              "CidrIp" : "0.0.0.0/0"
        },
        {
              "IpProtocol" : "tcp",
              "FromPort" : "22",
              "ToPort" : "22",
              "CidrIp" : "0.0.0.0/0"
        }
        ]
      }
    }

Coin Marketplace

STEEM 0.18
TRX 0.15
JST 0.029
BTC 62915.59
ETH 2542.92
USDT 1.00
SBD 2.63