Technical deep dive
Controlled third-party AWS connectivity: routes, ownership and drift
Treat partner connectivity as an owned policy: approve the inspection path, deploy explicit routes and observe specific configuration changes.
Chris Baran
Project work · · 7 min read
On this page
- Agree the connection before adding routes
- Make inspection a routing decision in both directions
- Deploy the approved association and destination
- Attach ownership to the prefix as well as the link
- Observe defined properties on a known cadence
- Separate route drift from an observation failure
- Finish the network and security handoffs
- Let the route set grow without moving ownership
A third-party platform needs access to an application. The connection is approved, a peering attachment becomes available, and the first test succeeds. The longer-lived questions remain: which destinations were approved, which inspection policy applies, who owns the connection, and what would reveal an unexpected route change?
For an oil and gas company, the engineering work brought together reusable Transit Gateway peering configuration, a custom AWS Config rule, focused tests and an operational runbook. It extended an existing Palo Alto inspection architecture. The useful pattern is to connect approval, deployment and ongoing observation around an explicitly owned connection.
The examples below are newly invented. A fictional partner uses documentation prefix 203.0.113.0/24; all resource references are symbolic.
Agree the connection before adding routes
Start with the application’s communication requirement: initiator, destination, protocol, port and business owner. Translate that into approved network prefixes and an inspection policy. A route’s existence says where traffic can go; the firewall policy decides which communication is allowed.
Record the network portion in a small contract. Keep the application’s allow rules in the corresponding security-policy review. Here, review_on is a human review point, not an automatic expiry mechanism. A useful approval records the communication requirement and the person responsible for renewing it.
{
"version": 1,
"partner": "example-partner",
"owner": "integration-operations",
"review_on": "2027-01-12",
"prefix": "203.0.113.0/24",
"attachment": "PARTNER_ATTACHMENT_ID",
"ingress_table": "INGRESS_ROUTE_TABLE_ID",
"destination_table": "POST_INSPECTION_ROUTE_TABLE_ID"
}The two table references describe different routing responsibilities. The attachment reference identifies the next hop for the partner prefix. Keeping these explicit lets reviewers compare a proposed route with the approved connection instead of interpreting an isolated CIDR addition.
Make inspection a routing decision in both directions
Transit Gateway peering requires explicit static routes. Accepting a peering does not exchange the networks behind each side through dynamic route propagation. Each side needs the appropriate routes for the intended communication. AWS’s peering documentation describes this static-routing model.
An attachment’s association selects the Transit Gateway route table used for traffic arriving through it. In the teaching model, the partner attachment uses an ingress table whose approved next hop leads towards inspection. Traffic returning to the Transit Gateway from inspection uses a different table to select its destination. Association and route propagation are separate controls. AWS explains those routing relationships.
For partner-to-workload traffic, the destination after inspection is the approved workload attachment. For workload-to-partner traffic, the destination after inspection is the partner peering attachment. Both directions need the intended ingress association, inspection path and onward route; the remote partner also owns its reverse routes.
Keep unintended routes and propagation from broadening those paths. Peering itself supports static routing only; propagation settings on other attachment types still need their own review. Stateful inspection also depends on compatible forward and return paths, including appliance-mode and inspection-VPC routing where applicable. AWS’s third-party appliance guidance explains the symmetry requirement.
Deploy the approved association and destination
This CloudFormation example declares the association, the route towards the partner after inspection, and its ownership record. It requires an accepted attachment and an existing network baseline. It does not create the inspection path or firewall policy. Resolve the symbolic references and settle any existing association ownership before using it in an approved deployment.
AWSTemplateFormatVersion: "2010-09-09"
Description: Fictional partner association, destination route and ownership record
Parameters:
Partner: {Type: String}
ConnectionOwner: {Type: String}
ReviewOn: {Type: String}
ApprovedPrefix: {Type: String}
PartnerAttachmentId: {Type: String, AllowedPattern: 'tgw-attach-[0-9a-f]{17}'}
IngressRouteTableId: {Type: String, AllowedPattern: 'tgw-rtb-[0-9a-f]{17}'}
DestinationRouteTableId: {Type: String, AllowedPattern: 'tgw-rtb-[0-9a-f]{17}'}
Resources:
PartnerIngress:
Type: AWS::EC2::TransitGatewayRouteTableAssociation
Properties:
TransitGatewayAttachmentId: !Ref PartnerAttachmentId
TransitGatewayRouteTableId: !Ref IngressRouteTableId
PartnerDestination:
Type: AWS::EC2::TransitGatewayRoute
Properties:
DestinationCidrBlock: !Ref ApprovedPrefix
TransitGatewayAttachmentId: !Ref PartnerAttachmentId
TransitGatewayRouteTableId: !Ref DestinationRouteTableId
OwnershipRecord:
Type: AWS::SSM::Parameter
Properties:
Type: String
Name: !Sub "/examples/partner-routes/${AWS::StackName}/prefix"
Value: !Ref ApprovedPrefix
Tags:
Partner: !Ref Partner
Owner: !Ref ConnectionOwner
ReviewOn: !Ref ReviewOnThe companion parameter generator reads the same contract, keeping deployment inputs aligned with the example’s expectations. CloudFormation provides distinct resources for the association and static route.
The Azure DevOps workflow packages the monitor from its canonical Lambda source and defines deployments for that stack and the peering configuration. Put the parameter diff, target environment and rollback into change review. Confirm repository protections, pipeline access and approval checks in the systems that administer them.
Attach ownership to the prefix as well as the link
An attachment can carry several relationships. A third-party prefix might travel over a shared internal peering alongside ordinary internal networks. Labelling that whole attachment as belonging to one partner obscures the distinction.
Per-prefix SSM metadata makes the relationship discoverable independently. The implementation associated prefix records with vendor information, a responsible contact, a change reference and the source stack. The fictional example uses a smaller record with an owner and review date.
Keep metadata and routing changes together. During review, the owner should be able to explain why the prefix remains necessary and identify the policy that permits its traffic. A stored change reference supplies context; it does not establish an integration with a ticketing system.
Observe defined properties on a known cadence
A configuration monitor needs a precise question. The attachment-level checks examine the expected association, absence of propagation entries, absence of ingress-table routes targeting that attachment, and presence of at least one destination-table route targeting it.
The separate per-prefix checks look for exact CIDR matches in the selected table classes. They do not establish the expected target or active state of every prefix route, detect every covering or more-specific alternative, or inspect firewall rules. A result must be interpreted within that scope.
The monitor definition combines configuration-change notifications with a periodic evaluation set to TwentyFour_Hours. AWS Config supports both change-triggered and periodic custom Lambda rules. Verify recorded resource coverage and the last successful evaluation; this cadence is not a promise of immediate detection for every route edit.
Keep the observer’s role narrow: network reads, reads within the metadata namespace, logging and submission of Config results. Route changes belong to the deployment path. Compliance-change notifications also need a tested subscription and a named responder; defining a notification destination alone does not complete that handoff.
Separate route drift from an observation failure
This original Python evaluator checks one useful slice: the declared destination route’s exact prefix, attachment, static type and active state. It validates the contract and snapshot first. Missing or malformed evidence raises a monitoring error; a complete snapshot missing the route produces a specific drift result.
from datetime import date
from ipaddress import IPv4Network
class MonitoringError(ValueError):
pass
def shape(value, keys):
if type(value) is not dict or set(value) != set(keys.split()):
raise MonitoringError("Missing, unexpected or invalid fields")
def strings(values):
if any(type(v) is not str or not v or v.strip() != v for v in values):
raise MonitoringError("Expected non-empty strings without outer spaces")
def prefix(value):
try:
network = str(IPv4Network(value, strict=True))
if network != value:
raise ValueError("Non-canonical network")
return network
except (ValueError, TypeError) as exc:
raise MonitoringError("Invalid IPv4 network") from exc
def validate_contract(contract):
shape(contract, "version partner owner review_on prefix attachment "
"ingress_table destination_table")
if type(contract["version"]) is not int or contract["version"] != 1:
raise MonitoringError("Unsupported contract version")
strings(v for k, v in contract.items() if k != "version")
prefix(contract["prefix"])
try:
if date.fromisoformat(contract["review_on"]).isoformat() != contract["review_on"]:
raise ValueError("Non-canonical date")
except ValueError as exc:
raise MonitoringError("Invalid review date") from exc
if contract["ingress_table"] == contract["destination_table"]:
raise MonitoringError("The example requires distinct route tables")
def validate_snapshot(snapshot, expected_table):
shape(snapshot, "version table complete routes")
if type(snapshot["version"]) is not int or snapshot["version"] != 1:
raise MonitoringError("Unsupported snapshot version")
strings([snapshot["table"]])
if snapshot["table"] != expected_table:
raise MonitoringError("Snapshot belongs to a different route table")
if snapshot["complete"] is not True:
raise MonitoringError("Route collection is incomplete")
if type(snapshot["routes"]) is not list:
raise MonitoringError("Routes must be an explicit list")
seen = set()
for route in snapshot["routes"]:
shape(route, "prefix attachment type state")
strings(route.values())
network = prefix(route["prefix"])
if network in seen:
raise MonitoringError("Duplicate destination makes the snapshot ambiguous")
seen.add(network)
if route["type"] not in {"static", "propagated"}:
raise MonitoringError("Unknown route type")
if route["state"] not in {"active", "blackhole"}:
raise MonitoringError("Unknown route state")
def evaluate(contract, snapshot):
validate_contract(contract)
validate_snapshot(snapshot, contract["destination_table"])
route = next((r for r in snapshot["routes"]
if r["prefix"] == contract["prefix"]), None)
if route is None:
return "NON_COMPLIANT", "Declared destination route is missing"
for field, expected in [("attachment", contract["attachment"]),
("type", "static"), ("state", "active")]:
if route[field] != expected:
return "NON_COMPLIANT", f"Declared destination has unexpected {field}"
return "COMPLIANT", "Declared destination route only: target, type and state match"complete: true is an assertion by the snapshot producer. A real collector must establish scope, finish pagination, handle API failures and enforce freshness before making it. The supplied snapshot is fictional and makes no AWS calls.
Download the companion files. Run the tests with python3 -B -m unittest -v and the example with python3 -B run_example.py. They use only Python’s standard library. Tests distinguish a wrong target, a missing route and a blackhole from incomplete collection, unknown fields and ambiguous evidence. They also demonstrate that this exact-route check does not evaluate competing routes.
If connecting such logic to AWS Config, fail the evaluation operation and report monitoring errors separately. NOT_APPLICABLE means the rule does not apply; it is not a substitute for unknown data. AWS explicitly rejects INSUFFICIENT_DATA from custom-rule Lambda submissions. See the Evaluation API contract.
Finish the network and security handoffs
Direct Connect advertisement is a separate decision. For a Transit Gateway association, the Direct Connect gateway originates the configured allowed prefixes towards on-premises. It does not export the Transit Gateway route table generically. AWS documents the allowed-prefix behaviour.
The operating procedure keeps required advertisement changes as a separately approved CLI or console action. Name the responsible network team, review the prefix change and verify the received advertisement. A successful peering deployment does not complete that step.
Likewise, agree the firewall rules with the security team and reverse routes with the partner. Verify approved and denied application flows, inspect the relevant firewall evidence, and check the return path. Route observations alone cannot prove firewall enforcement, packet traversal or the absence of every bypass.
The runbook should turn a concrete drift result into work: identify the affected route or association, contact its owner, review the intended state and correct the configuration through the deployment process. Monitoring supplies evidence for that decision; it does not automatically remediate the network.
Let the route set grow without moving ownership
As the configuration expanded, the template gained a routes-only mode and more compact per-prefix metadata inputs. One stack retained attachment and association ownership; additional stacks could add routes and metadata without taking over that lifecycle. This addressed template scale while preserving a clear owner for the connection.
Tests strengthened the same operating model by isolating individual failures, such as a wrong association or a missing destination route. The practical outcome is an inspectable relationship between approved paths, ownership and specific observations. At the next review, the team can identify what was intended, which check changed and who should act.
Bring one workload’s external dependencies to an AWS Workload Foundations Assessment. We review its network boundaries and operating checks, with scope and a fixed fee agreed after a qualification call.
