The Cisco ASA (Adaptive Security Appliance) is primarily designed to be a NAT firewall; most of the setup examples assume that you will be configuring NAT. However with sufficient effort it is possible to use it in an environment that has enough real world addresses to avoid the pain of NAT. Unfortunately there doesn't seem to be much documentation about use in this manner easily available.

The Cisco ASA also really wants to be the boundary firewall for the network, sitting directly between the outside edge of the network and the inside of the network. While it is possible to use it in other configurations, to use a different subset of the functionality (eg, use it as just a VPN gateway, with set of other routers and firewalls, such as a VPN router on a stick), the limited set of advanced routing features available on the Cisco ASA make this complicated.

One of the more obviously missing features when trying to use the Cisco ASA as anything other than an edge NAT firewall (optionally with VPN functionality) is the lack of Policy Based Rating (PBR) support (see eg confirmation of lack of policy based routing). Such source based rating is useful for working with a load balancer, or any other non-trivial network with other routing devices -- especially where remote VPN users should be treated differently from general traffic from the Internet (a common case in a corporate environment, and generally the reason for creating a VPN in the first place). It is particularly helpful where remote VPN users need to be treated as if there requests come from inside the network (eg, inside a border firewall) when accessing external resources.

There are a couple of exceptions to this lack of policy based routing, and with some ingenuity it is sometimes possible to adapt these minimal forms of PBR into a sufficient selective routing feature to achieve what you want. The first is that you can use the static NAT functionality to steer some outgoing traffic by source/destination port (note that example is using the older ASA NAT syntax; another example). And the second, which seems to be barely referenced in the documentation, is that you can have a different default route for traffic arriving by VPN from the default route for traffic arriving unencrypted.

The use of two default gateways -- what Cisco calls a DGG (Default Gateway), and a DTGW (Default Tunnelled-Traffic Gateway) -- provides a "1-bit" (tunnelled or not) selector for sending traffic in different directions. The Cisco page describing Configuring Tunnel Default Gateways uses Policy Based Routing on IOS (or VRFs), and provides the most detailed description of the Cisco ASA feature to route tunnelled traffic differently (not very detailed).

On the Cisco ASA the approach is:

route outside 0.0.0.0 0.0.0.0 A.B.C.D 1
route inside  0.0.0.0 0.0.0.0 W.X.Y.Z tunneled

where:

  • "0.0.0.0 0.0.0.0" is the expression of "default route"

  • "outside" is the "nameif" given to the external interface

  • "inside" is the "nameif" given to the internal interface

  • "A.B.C.D" is the default gateway out to the outside world to use for traffic arriving unencrypted, and outgoing the VPN encapsulated packets

  • "W.X.Y.Z" is the default gateway out to the rest of the network to use for traffic arriving via a VPN (eg, towards the rest of the internal network)

  • "tunneled" is the magic word (complete with USA spelling) to enable this "1-bit PBR"

This functionality applies only to the default route; attempts to use it on any other route are rejected with an error that it applies only to the default route. This feature rates only a one paragraph mention in the Cisco ASA configuration guide discussion of static routes, viz:

"You can define a separate default route for tunneled traffic along with
the standard default route. When you create a default route with the
tunneled option, all traffic from a tunnel terminating on the adaptive
security appliance that cannot be routed using learned or static routes,
is sent to this route. For traffic emerging from a tunnel, this route
overrides over any other configured or learned default routes."

which is unfortunate because if you can simplify your ASA routing table so that all situations where different routing is required can fall through to the default route, then this "1-bit PBR" is sufficient to resolve the need for policy based routing. It is particularly useful where you are attempting to provide Internet access to your VPN users, via the VPN (the non-split-tunnel scenario), and want the traffic from your VPN users to follow the same path out of the network as internal users (even though the external interface of the ASA isn't connected in the same location as internal users -- eg, the external interface of the ASA is connected to a DMZ). In my case with some thought it was possible to explicitly route all networks inside the border firewall across the inside interface, and then allow the two default routes to correctly steer traffic arriving from VPN users and other traffic.

Without this "1-bit PBR" your choices are basically to do NAT (where the different internal and external addresses can naturally be routed differently), and/or to deal with asymmetric routing in your network. In the latter case to provide Internet access via the VPN you effectively end up doing "hairpinning" (more examples online), relying on the (off by default):

same-security-traffic permit intra-interface

command (introduced with ASA 7.x) to allow VPN to non-VPN (and non-VPN to VPN) traffic back out "same" interface (sadly another limitation of the ASA is that tunnelled traffic does not arrive over an encrypted psuedo interface, it is treated as arriving over the external interface -- thus leading the ASA to consider VPN traffic going back out to the Internet to be going through the "same" interface :-( ). When you start down that path you may well also need to deal with some of your routing being asymmetric, using TCP State bypass (which only works for TCP; you'll have statelessly allow UDP and ICMP in both directions over all affected interfaces). (Other examples: Hairpinning from user VPN into site VPN, Cisco feature description, and an example hairpin for Internet access. Sadly if the ASA were to treat tunnelled encrypted traffic as arriving on a different interface from unencrypted traffic, none of this confusion would be necessary; it would even look like sending traffic out the same interface. OpenBSD's enc0 is one of the few designs to get this right; even Linux which used to do it correctly moved to a non-separate-interface design some years back.)

(This list of Cisco ASA configuration guides may be of use. It may also be possible to use Identity NAT with an interface specified (rather than route-lookup) on a Cisco ASA with 8.4(2) or higher software as another alternative to policy based routing support; I haven't tried this (more discussion). Packet capture on the ASA can also be useful for debugging this situation, although note in the "same interface' situation traffic won't leave any interface of the ASA without the "intra-interface" setting mentioned above. The PIX/ASA troubleshooting guide, and Lan-to-Lan and Remote Access VPN trouble shooting guide may also have helpful hints. Also ASA 5xxx CLI configuration guide, 8.2 (and 8.4 CLI) and ASA 5xxx command reference, 8.2.)

ETA, 2012-05-09: As another "gotcha", beware that while the ASA will add stateful entries (to allow reply traffic) for TCP and UDP by default, it will not permit ICMP replies by default, which amongst other things breaks "ping" as soon as you start adding access lists. There are several work arounds, including allowing each ICMP reply type you want individually, but on modern PIX/ASA one of the most expedient approaches is to instruct the ASA to inspect ICMP (ie, a protocol specific handler):

policy-map global_policy
  class inspection_default
     inspect icmp

at which point it will handle it like any other protocol needing firewall assistance (of which the ASA and most stateful firewalls have a long list).
You can check it is working by looking at the connection tracking state:

show conn all

and you should see some ICMP "connections". "packet-tracer" can also be helpful to debug situations like this, although ones that depend on connection state to work can only be debugged when the connection state has been created.... and there's no way to specify a packet arrived in a VPN tunnel. Beware that this ICMP inspection will generate a lot of logging if you have logging enabled, potentially filling the on-ASA very rapidly. Also beware that ICMP to the ASA itself is handled separately from the access-lists, by the top level "icmp permit" command; and defaults to always responding.

And finally beware that the default in recent ASA is that VPNs will bypass the access lists as if "sysopt connection permit-vpn" has been entered (it is the default). You either need to use "vpn-filter" to do filtering of VPNs, or run "no sysopt connection permit-vpn" and configure ACLs for all VPN traffic too. ("show run all sysopt" will show all the defaults; "show run sysopt" will show your configured differences.)