NAT66 and IPv6 ULA on Juniper SRX

Sometimes, you do not have access to enough public address space to number all your subnets. This is especially recurrent in virtualized environments where network segmentation is a natural design choice. In such environments, you may have several VLANs and routing instances (call them routing domains, or contexts, depending of the vendor terminology you're familiar with), and for each, comes a unique set of subnets. Every network operator knows how painful IP address management is, and we all want to avoid renumbering our network, especially if the following account for hundreds, if not thousands of subnets. You certainly also figured out that Network Address Translation (NAT) could help in this manner, but do you know its benefits could be as well applied to the IPv6 world?

Prior to digging into the details, lets take a use case I recently came across. I had to number 5 different subnets and several routing instances for a relatively simple application stack. The latter is layered out as follow:

The first subnet, is the public facing network to the global internet, and it is terminated on a dual-stacked firewall. The remaining subnets are used to respectively address the web servers, the application servers and the databases. They has been logically separated as it's common practice in environments where security and scalability are of prime importance (why shouldn't be otherwise). As you can see, there's a unique subnet per function of the application stack, so we can easily segment traffic, and distinguish flows to and from the various types of services. Web servers establishes connectivity to application servers, and the latter establishes connectivity to databases servers. Why allowing web servers to potentially establish connectivity to the database servers if it's not strictly needed? What if an application server has been compromised and a attacker spreads attacks directly to the outside world? The design choice here is to isolate services by their function, so we can easily mitigate potentials security issues, and so from a central point of management.

Most of the application stacks' clients are located on the internet and are running IPv4. We also want our services to be available over IPv6, and to clients behind a Virtual Private Network (VPN). For both address families, we didn't get enough public addresses to number all our servers. In fact, the transit provider offered us only a /64 prefix; not enough address space to number our five IPv6 subnets. A Provider-Assigned (PA) /48 prefix would have done the job, however we would have been locked to the transit provider. A second option would have been to get a Provider-Independent (PI) IPv6 prefix from a RIR, but it would have required paperwork. Finally, a third option, would have been to number our services out of a IPv6 Unique Local Address (ULA) prefix. This last option is particularly interesting because it allow us to number every servers independently of the transit provider's address space. In fact, the intent here is also to be able to migrate the whole stack to another hosting provider, if necessary, and thus without having to renumber all the servers and the network segments in the process.

To provide services to the outside world, we have to translate the IPv6 ULAs to the global IPv6 addresses. In our case, it's also a requirement for IPv4, due to the limited public address space for this address family. Hopefully, only web servers do provide services to the VPN clients and to the outside world, therefore our NAT gateway have to run only a few number of translation rules. As every data coming in and out of the application stack is passing through the above mentioned firewall, it also becomes the logical candidate for the NAT functions.

As already mentioned previously, in order to make the services available to the IPv6 internet, we have to somehow translate the servers' IPv6 ULA addresses to a globally-reachable IPv6 address space. This can be done by using destination NAT, in other words, we will translate the destination addresses of packets entering our network. and we will translate the source addresses of packets exiting it. Several Destination NAT translations types exists, but in our case, we will use PAT, which stands for Port Address Translation. As we have a limited number of services to make publicly available, namely HTTP and HTTPS, we may want to translate the destination address and the port simultaneously. It also brings an additional layer of security and simplification, because we filter out traffic toward destination ports not matching existing translation rules and we have to remember only one global IPv6 address for our DNS records.

The example below show how to configure a Juniper SRX for Destination NAT with port tcp/80 (http):

Create a destination NAT pool.

The pool defines the local IPv6 ULA address of a server and a given port number.

[edit security nat destination pool dst-nat-v6-frontend01-p80]
eprom@vsrx01# set address fd40:2001:db8::1 port 80 
Create a destination NAT rule-set.

The rule-set groups various translation rules for a given zone. Here, destination NAT is performed on traffic entering the 'public' zone.

[edit security nat destination rule-set frontend-static-dnat]
eprom@vsrx01# set from zone public
Configure a destination NAT rule.

The translation rule defines the match conditions the inbound traffic is subject to, and the action(s) to be performed. Here, we want the matched destination address and port pair to be translated using the previously defined pool.

[edit security nat destination rule-set frontend-static-dnat]
eprom@vsrx01# set rule global-http-v6 match destination-address 2001:db8:cafe:beef::1
eprom@vsrx01# set rule global-http-v6 match destination-port 80
eprom@vsrx01# set rule global-http-v6 then destination-nat pool dst-nat-v6-frontend01-p80
Define the server IPv6 ULA address into the zone address book.

To reference our server multiple times in our configuration and to ease visibility, we define our IPv6 addresses inside the servers' zone address book.

[edit security zones security-zone frontend]
eprom@vsrx01# set address-book address frontend-01-v6 fd40:2001:db8::1
Define a security policy for the translated traffic.

Finally, we allow the translated traffic between the 'public' and the 'frontend' zone, where our web servers are located.

[edit security policies from-zone public to-zone frontend]
eprom@vsrx01# set policy permit-http match source-address any
eprom@vsrx01# set policy permit-http match destination-address frontend-01-v6
eprom@vsrx01# set policy permit-http match application  junos-http
eprom@vsrx01# set policy permit-http then permit
Configuration Result

Repeat the configuration steps above for other services (e,g. https). Please note that a rule-set can hold both IPv4 and IPv6 translation rules, which makes dual-stack configurations easy to read and to manage.

eprom@vsrx01# show security nat
destination {
    pool dst-nat-v6-frontend01-p80 {
        address fd40:2001:db8::1/128 port 80;
    }
    pool dst-nat-v6-frontend01-p443 {
        address fd40:2001:db8::1/128 port 443;
    }
    rule-set frontend-static-dnat {
        from zone public;
        rule global-http-v6 {
            match {
                destination-address 2001:db8:cafe:beef::1/128;
                destination-port 80;
            }
            then {
                destination-nat {
                    pool {
                        dst-nat-v6-frontend01-p80;
                    }
                }
            }
        }
        rule global-https-v6 {
            match {
                destination-address 2001:db8:cafe:beef::1/128;
                destination-port 443;
            }
            then {
                destination-nat {
                    pool {
                        dst-nat-v6-frontend01-p443;
                    }
                }
            }
        }
    }
}

eprom@vsrx01# show security policies from-zone public to-zone frontend 
policy permit-http {
    match {
        source-address any;
        destination-address frontend-01-v6
        application [ junos-http junos-https ];
    }
    then {
        permit;
    }
}

The customers should now be able to access the web server's HTTP and HTTPS services. To verify the firewall effectively allows the traffic and do maintains the sessions states, you can use the show security flow session command while connecting to a service using the telnet utility, as shown below:

eprom@adm2:~$ telnet -6 2001:db8:cafe:beef::1 80
Trying 2001:db8:cafe:beef::1...
Connected to 2001:db8:cafe:beef::1.
Escape character is '^]'.
GET /
Connection closed by foreign host.

eprom@vsrx01> show security flow session family inet6 application http    
Session ID: 158060, Policy name: permit-http/27, Timeout: 298, Valid
  In: 2001:620:2010:102:22cf:30ff:fe3e:6008/44647 --> 2001:db8:cafe:beef::1/80;tcp, If: ge-0/0/0.0, Pkts: 2, Bytes: 152
  Out: fd78:62fd:2ddc::2/80 --> 2001:620:2010:102:22cf:30ff:fe3e:6008/44647;tcp, If: ge-0/0/1.0, Pkts: 1, Bytes: 80
Total sessions: 1

The combination of IPv6 ULAs and NAT66 allows us to quickly provide services over IPv6, while keeping the servers addressing independent of any transit provider. It also allows us to work around some administrative problems and limitations, such as the need for PI addresses or the need for a larger address space. Another great benefit of NAT66 is to avoid dual-stacking all our servers, and thus to maintain two different network-layer protocols. Finally, it may also helps us in keeping the configuration of services like DNS simpler and also to efficiently enable additional features like SLB.

About the author Nicolas Chabbey

Nicolas Chabbey is a Network Engineer certified with Cisco Systems and Juniper Networks. He has begun his career in 2003, and has designed, implemented and maintained networks for enterprises and service providers. When he is not behind a computer, he is riding his mountain bike across the Swiss alps.

Previous Home Next

Comments

blog comments powered by Disqus