Skip to content

I-ALiRT - vpn tunnel - #1334

Merged
laspsandoval merged 17 commits into
IMAP-Science-Operations-Center:devfrom
laspsandoval:vpn_tunnel
Jul 24, 2026
Merged

I-ALiRT - vpn tunnel#1334
laspsandoval merged 17 commits into
IMAP-Science-Operations-Center:devfrom
laspsandoval:vpn_tunnel

Conversation

@laspsandoval

@laspsandoval laspsandoval commented May 13, 2026

Copy link
Copy Markdown
Contributor

What we provide to NOAA:

  • IKE Gateway IPs
  • BGP IP LASP
  • AWS-side ASN
  • I-ALiRT's EIP + port
  • LASP's advertised BGP prefixes

What NOAA provides to us:

  • Their border router public IPs (WASH + DENV) (stackbuilder.py:460)
  • Their ASN (ialirt_vpn_construct.py:124)
  • The PSK (stackbuilder.py:446)

Neither side "provides" - needs to go back to NOAA as a platform limitation:

  • BGP MD5 string - AWS's managed Site-to-Site VPN doesn't support this.

Notes:

  • NOAA has two border routers — one in McLean, VA (WASH) and one in Denver, CO (DENV) — each with a public IP. Two sites exist purely for redundancy: if one goes down, traffic reroutes through the other. Each NOAA router opens an IPSec (IKEv2) tunnel to AWS, authenticated with a shared secret (PSK).

Why we used Transit Gateway:

A Virtual Private Gateway (VGW) is the "default" way to terminate a Site-to-Site VPN. It attaches directly to a VPC and injects routes into that VPC's subnet route tables. A VGW cannot route decrypted VPN traffic to a NAT Gateway.

Why that's a problem here: I-ALiRT's actual endpoint is an EC2 instance in an Auto Scaling Group. Its private IP isn't stable. If the ASG replaces the instance, the private IP changes. What is stable is its Elastic IP, which is reached by going out through a NAT Gateway. So NOAA's decrypted traffic needs to land in the VPC and then get handed to the NAT Gateway so it can reach that Elastic IP - exactly the hop a VGW can't do.

A Transit Gateway can do that hop. A TGW attaches to the VPC and its traffic follows whatever the subnet's own route table says - including a NAT Gateway route. So terminating the VPN on a TGW instead of a VGW means the decrypted NOAA traffic gets funneled through the NAT Gateway, out to the Elastic IP, and hits the instance the same way everyone else's traffic does.


Screenshot 2026-07-22 at 9 40 03 AM

- Step 1: NOAA sends data

The packet has:

  • Source IP: NOAA's internal private IP
  • Destination IP: the I-ALiRT EIP

- Step 2: NOAA's border router encrypts the packet

The router has a rule: Traffic destined for the I-ALiRT EIP goes through the VPN tunnel

The router wraps the original packet in an encrypted IPSec envelope. The outer envelope has:

  • Source IP: NOAA border router public IP (WASH) or (DENV)
  • Destination IP: AWS's auto-assigned VPN tunnel endpoint public IP

- Step 3: Travels across public internet

- Step 4: AWS Transit Gateway decrypts the packet

  • Note: NOAA border router public IPs go into the CfnCustomerGateway, which is essentially AWS's record of "this is NOAA's router, trust it.

AWS decrypts the envelope using the pre-shared key (Secrets Manager, /ialirt/noaa/noaa-vpn-psk).

The outer envelope is discarded. The original inner packet is restored:

  • Source IP: NOAA's private internal IP (TBD Wallops/Suitland address)
  • Destination IP: the I-ALiRT EIP

- Step 5: Transit Gateway routes the packet into the VPC

TGW route table sends it through the VPC attachment, into a private subnet. Packet is unchanged.

- Step 6: Private subnet routes the packet to the NAT Gateway

Default route (0.0.0.0/0) sends it there, since the EIP isn't inside the VPC's own address range. The NAT Gateway rewrites the source IP to its own EIP (NOAA's original source IP is gone at
this point):

  • Source IP: NAT Gateway's own EIP
  • Destination IP: the I-ALiRT EIP

- Step 7: NAT Gateway hands off to Internet Gateway, which translates EIP → private IP

- Step 8: Security group check

SG sees source = NAT Gateway's own EIP (not NOAA's real IP), checked against the allow-list.

- Step 9: Container receives packet


Testing
To validate the NOAA N-Wave Site-to-Site VPN connection ahead of the real NOAA onboarding, I stood up an EC2 instance running strongSwan as a stand-in for NOAA's border router, configured
with the IKEv2/AES-256-CBC/SHA2-256/DH group14 parameters specified in the ICD, and deployed the IalirtStack CDK infrastructure — which routes the NOAA VPN connection through a Transit
Gateway to a NAT Gateway and I-ALiRT's stable Elastic IP in a sandbox AWS account for testing. This architecture was tested end-to-end on the WASH site's Tunnel 1, with a TCP connection successfully established from the strongSwan test host through the IPsec tunnel, BGP-derived routing, NAT Gateway, and security group to I-ALiRT's Elastic IP, confirming actual data packets traverse the full path.

Detailed reproducible instructions

  1. Prerequisites: A running EC2 acting as the test "NOAA router" with strongSwan + FRR already installed (we reused an existing one: dev account).

  2. Confirm the stack deployed the VPN resources
    aws cloudformation describe-stack-resources --stack-name IalirtStack
    --profile lcs --region us-west-2
    Look for AWS::EC2::VPNConnection, AWS::EC2::CustomerGateway, AWS::EC2::TransitGateway* entries.

  3. Look up the tunnel endpoint you're bringing up (e.g. WASH)
    aws ec2 describe-vpn-connections --vpn-connection-ids
    --region us-west-2 --profile lcs
    --query 'VpnConnections[].Options.TunnelOptions[].{OutsideIp:OutsideIpAddress,InsideCidr:TunnelInsideCidr}'
    --output json
    Take Tunnel 1's OutsideIp and InsideCidr.

  4. Point strongSwan at that tunnel
    On the test EC2, edit /etc/swanctl/conf.d/noaa-aws.conf: set remote_addrs, the remote { id = ... } block, and the secrets.ike-tunnel1.id-2 entry all to the OutsideIp from step 2.

  5. Point FRR's BGP config at the AWS-side inside IP
    Edit /etc/frr/frr.conf: router bgp <NOAA ASN, e.g. 64583>, neighbor <AWS-side inside IP, e.g. x.x.x.x/30's .1> remote-as 64512 (AWS's amazon_side_asn), and a network statement for whatever
    prefix you want to test-advertise.

  6. Bring the tunnel up
    sudo swanctl --load-all
    sudo swanctl --initiate --child aws-tunnel1

  7. Verify BGP came up
    sudo vtysh -c "show bgp summary"
    Expect ESTABLISHED against the AWS-side inside IP.

  8. Confirm from the AWS side
    aws ec2 describe-vpn-connections --vpn-connection-ids
    --region us-west-2 --profile lcs --query 'VpnConnections[].VgwTelemetry' --output json
    Expect Status: UP and a nonzero AcceptedRouteCount on that tunnel's OutsideIpAddress.

  9. Find I-ALiRT's current Elastic IP (dynamically Lambda-assigned per instance, not static — always look it up fresh)
    aws ec2 describe-instances
    --filters "Name=tag:aws:cloudformation:stack-name,Values=IalirtStack" "Name=instance-state-name,Values=running"
    --region us-west-2 --profile lcs
    --query 'Reservations[].Instances[].{InstanceId:InstanceId,PublicIp:PublicIpAddress}' --output json

  10. Send test traffic, explicitly sourced from the test EC2's private IP
    echo "test" | nc -v -s 7563 -i 1
    Expect "Connection ... succeeded!".

@laspsandoval

Copy link
Copy Markdown
Contributor Author

I think we won't need this:

d) The following networks/prefixes requiring access to NOAA resources will be routed to NOAA N-Wave via static routing by LASP:
i) ###.###.##.#/26

if we use BGP

@laspsandoval laspsandoval linked an issue May 13, 2026 that may be closed by this pull request
@ahotasu

ahotasu commented May 14, 2026

Copy link
Copy Markdown

@laspsandoval This is a great fix for security purposes, but the system (LASP's IMAP? AWS infrastructure) still won't be covered by an SSP. Is Rachel going to add the AWS infrastructure to LASP's institutional SSP?

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds I-ALiRT Site-to-Site VPN infrastructure for NOAA N-Wave connectivity and wires it into the SDS CDK deployment.

Changes:

  • Adds a Virtual Private Gateway and public subnet route propagation.
  • Adds a new I-ALiRT VPN construct for NOAA customer gateways and VPN connections.
  • Retrieves VPN PSK/router IP configuration and adds a placeholder for NOAA ECS access rules.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 7 comments.

File Description
sds_data_manager/utils/stackbuilder.py Retrieves NOAA VPN configuration and instantiates the VPN construct.
sds_data_manager/constructs/networking_construct.py Adds VGW creation, VPC attachment, and route propagation.
sds_data_manager/constructs/ialirt_vpn_construct.py Defines NOAA customer gateways, VPN connections, and tunnel crypto settings.
sds_data_manager/constructs/ialirt_processing_construct.py Adds a TODO placeholder for NOAA security group ingress.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread sds_data_manager/utils/stackbuilder.py Outdated
Comment thread sds_data_manager/constructs/networking_construct.py Outdated
Comment thread sds_data_manager/constructs/ialirt_processing_construct.py Outdated
Comment thread sds_data_manager/constructs/ialirt_vpn_construct.py
Comment thread sds_data_manager/constructs/networking_construct.py Outdated
Comment thread sds_data_manager/constructs/networking_construct.py Outdated
Comment thread sds_data_manager/utils/stackbuilder.py Outdated
@laspsandoval

Copy link
Copy Markdown
Contributor Author

Outdated.

@github-project-automation github-project-automation Bot moved this to Done in IMAP Jun 11, 2026
@laspsandoval laspsandoval reopened this Jul 17, 2026
@laspsandoval
laspsandoval force-pushed the vpn_tunnel branch 2 times, most recently from 8d8ef84 to b534578 Compare July 20, 2026 19:17
@laspsandoval
laspsandoval requested a review from Copilot July 20, 2026 19:18
@laspsandoval laspsandoval added this to the July 2026 milestone Jul 20, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

Comment thread sds_data_manager/utils/stackbuilder.py Outdated
Comment thread sds_data_manager/constructs/networking_construct.py Outdated
Comment thread sds_data_manager/constructs/ialirt_vpn_construct.py
Comment thread sds_data_manager/constructs/ialirt_vpn_construct.py

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

Comments suppressed due to low confidence (2)

sds_data_manager/utils/stackbuilder.py:450

  • The NOAA VPN resources are created unconditionally in build_sds(). This will break deployments in accounts/environments where the required SSM parameters and Secrets Manager secret don't exist (CloudFormation will fail resolving them), and it also forces creation of a Transit Gateway/VPN in every environment. Consider gating this whole block behind an explicit account_config flag (e.g. enable_noaa_vpn) and/or limiting it to the intended account(s).
    # Retrieve the NOAA VPN pre-shared key from Secrets Manager.
    # Store the PSK under the key "psk" in a secret named
    # "/ialirt/noaa/noaa-vpn-psk" before deploying this stack.
    noaa_vpn_psk = (
        secretsmanager.Secret.from_secret_name_v2(
            ialirt_stack, "NoaaVpnPsk", "/ialirt/noaa/noaa-vpn-psk"
        )
        .secret_value_from_json("psk")
        .unsafe_unwrap()
    )

sds_data_manager/constructs/ialirt_vpn_construct.py:75

  • New infrastructure construct IalirtVpnConstruct introduces non-trivial CDK/CloudFormation resources (CustomerGateways, VPNConnections, tunnel option specs) but there are no corresponding aws_cdk.assertions-based unit tests (tests/infrastructure has this pattern for other constructs). Adding a template assertion test would help prevent accidental changes to tunnel parameters and resource counts.
        tunnel = ec2.CfnVPNConnection.VpnTunnelOptionsSpecificationProperty(
            pre_shared_key=psk,
            ike_versions=[
                ec2.CfnVPNConnection.IKEVersionsRequestListValueProperty(value="ikev2")
            ],
            phase1_encryption_algorithms=[
                ec2.CfnVPNConnection.Phase1EncryptionAlgorithmsRequestListValueProperty(
                    value="AES256"
                )
            ],

Comment thread sds_data_manager/utils/stackbuilder.py Outdated
Comment thread sds_data_manager/utils/stackbuilder.py Outdated
Comment thread sds_data_manager/constructs/ialirt_vpn_construct.py

@lacoak21 lacoak21 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! I tried tracking the flow down and it looks good. This was on a high level though so the testing will be key. Great work!!

Comment thread sds_data_manager/constructs/ialirt_vpn_construct.py
Comment thread sds_data_manager/utils/stackbuilder.py Outdated
Comment thread sds_data_manager/utils/stackbuilder.py Outdated
@laspsandoval
laspsandoval merged commit 83478cb into IMAP-Science-Operations-Center:dev Jul 24, 2026
2 checks passed
@laspsandoval
laspsandoval deleted the vpn_tunnel branch July 24, 2026 19:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

I-ALiRT - Create VPN Tunnel

4 participants