Skip to content

Commit 6dd0b4e

Browse files
committed
Merge upstream/dev into use-window-instead-of-subquery
Upstream IMAP-Science-Operations-Center#1533 already landed the window-function version resolution as api_lambdas/utils.build_latest_version_query, so this branch's duplicate latest_version_query.py and FILE_ID_COLUMNS definition are dropped in favor of upstream's. release_api.py takes upstream's manifest-line release wholesale; the release performance test now exercises latest_science_release directly since the old lambda params are gone. Assisted-by: Claude
2 parents 7dae958 + b6ba928 commit 6dd0b4e

32 files changed

Lines changed: 1329 additions & 671 deletions

sds_data_manager/constructs/ialirt_processing_construct.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,10 @@ def create_ecs_security_group(self):
107107
"params": ["kiel"],
108108
"ports": [7564],
109109
},
110+
"noaa": {
111+
"params": ["noaa"],
112+
"ports": [7565],
113+
},
110114
"uksa": {
111115
"params": ["uksa"],
112116
"ports": [7566, 7567],
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
"""Configure the I-ALiRT VPN connections to NOAA N-Wave."""
2+
3+
from aws_cdk import aws_ec2 as ec2
4+
from constructs import Construct
5+
6+
7+
class IalirtVpnConstruct(Construct):
8+
"""NOAA N-Wave customer gateways and VPN connections for I-ALiRT."""
9+
10+
def __init__(
11+
self,
12+
scope: Construct,
13+
construct_id: str,
14+
transit_gateway_id: str,
15+
psk: str,
16+
wash_ip: str,
17+
denv_ip: str,
18+
**kwargs,
19+
) -> None:
20+
"""Create NOAA N-Wave customer gateways and VPN connections.
21+
22+
Parameters
23+
----------
24+
scope : Construct
25+
Parent construct.
26+
construct_id : str
27+
A unique string identifier for this construct.
28+
transit_gateway_id : str
29+
The Transit Gateway to attach the VPN connections to. A Transit
30+
Gateway is used (rather than a Virtual Private Gateway) because a
31+
VGW cannot route decrypted VPN traffic to a NAT Gateway, and a NAT
32+
Gateway is required so NOAA's traffic reaches I-ALiRT via its
33+
stable Elastic IP instead of an EC2 private IP that changes
34+
whenever the Auto Scaling Group replaces the instance.
35+
psk : str
36+
Pre-shared key for IKE authentication. Pass a CDK token from
37+
``secret_value_from_json(...).unsafe_unwrap()`` so the value is
38+
resolved by CloudFormation at deploy time and never appears in
39+
the template.
40+
wash_ip : str
41+
NOAA border router public IP at McLean, VA (WASH), retrieved from SSM.
42+
denv_ip : str
43+
NOAA border router public IP at Denver, CO (DENV), retrieved from SSM.
44+
kwargs : dict
45+
Keyword arguments.
46+
"""
47+
super().__init__(scope, construct_id, **kwargs)
48+
49+
# Define the crypto settings for the IPSec tunnel, as specified
50+
# in the N-Wave ICD (NOAA0550).
51+
#
52+
# Phase 1 (IKE) — the handshake phase where both sides authenticate each other
53+
# and agree on encryption keys. Uses pre-shared key (PSK)
54+
# resolved at deploy time.
55+
# - IKEv2 only (NOAA requirement)
56+
# - AES-256 encryption
57+
# - SHA2-256 integrity
58+
# - DH group 14 for key exchange
59+
# - 28800s (8 hour) lifetime
60+
#
61+
# Phase 2 (ESP) — the data phase where actual traffic is encrypted.
62+
# - AES-128 or AES-256 encryption
63+
# - HMAC-SHA2-256-128 integrity
64+
# - DH group 14 (PFS — Perfect Forward Secrecy)
65+
# - 3600s (1 hour) lifetime
66+
tunnel = ec2.CfnVPNConnection.VpnTunnelOptionsSpecificationProperty(
67+
pre_shared_key=psk,
68+
ike_versions=[
69+
ec2.CfnVPNConnection.IKEVersionsRequestListValueProperty(value="ikev2")
70+
],
71+
phase1_encryption_algorithms=[
72+
ec2.CfnVPNConnection.Phase1EncryptionAlgorithmsRequestListValueProperty(
73+
value="AES256"
74+
)
75+
],
76+
phase1_integrity_algorithms=[
77+
ec2.CfnVPNConnection.Phase1IntegrityAlgorithmsRequestListValueProperty(
78+
value="SHA2-256"
79+
)
80+
],
81+
phase1_dh_group_numbers=[
82+
ec2.CfnVPNConnection.Phase1DHGroupNumbersRequestListValueProperty(
83+
value=14
84+
)
85+
],
86+
phase1_lifetime_seconds=28800,
87+
phase2_encryption_algorithms=[
88+
ec2.CfnVPNConnection.Phase2EncryptionAlgorithmsRequestListValueProperty(
89+
value="AES128"
90+
),
91+
ec2.CfnVPNConnection.Phase2EncryptionAlgorithmsRequestListValueProperty(
92+
value="AES256"
93+
),
94+
],
95+
phase2_integrity_algorithms=[
96+
ec2.CfnVPNConnection.Phase2IntegrityAlgorithmsRequestListValueProperty(
97+
value="SHA2-256"
98+
)
99+
],
100+
phase2_dh_group_numbers=[
101+
ec2.CfnVPNConnection.Phase2DHGroupNumbersRequestListValueProperty(
102+
value=14
103+
)
104+
],
105+
phase2_lifetime_seconds=3600,
106+
)
107+
108+
# Customer Gateway - AWS's record of NOAA's router so that AWS can recognize
109+
# and accept the incoming encrypted packets.
110+
111+
# Every AWS Site-to-Site VPN connection automatically provisions
112+
# two auto-assigned tunnel IPs.
113+
# These LASP IKE Gateways must be given to NOAA.
114+
self.vpn_connections: dict[str, ec2.CfnVPNConnection] = {}
115+
for site, ip in {"WASH": wash_ip, "DENV": denv_ip}.items():
116+
# AWS needs to know the router's public IP and ASN to establish the tunnel.
117+
# bgp_asn=64583 is NOAA's ASN per the ICD. This must match the ASN
118+
# configured on NOAA's actual router — AWS silently rejects the BGP
119+
# session (not the tunnel itself) if the peer AS doesn't match what's
120+
# registered here.
121+
cgw = ec2.CfnCustomerGateway(
122+
self,
123+
f"NoaaCustomerGateway{site}",
124+
bgp_asn=64583,
125+
ip_address=ip,
126+
type="ipsec.1",
127+
)
128+
129+
# Create the VPN connection between our Transit Gateway (TGW) and
130+
# NOAA's customer gateway. Each connection gets two tunnels by
131+
# default (AWS requirement for redundancy) — both use the same
132+
# crypto settings. BGP is used (static_routes_only=False) so that
133+
# if one site (WASH or DENV) goes down, BGP automatically reroutes
134+
# traffic through the other. Data flows one way: NOAA sends to us.
135+
# We do not send to NOAA.
136+
self.vpn_connections[site] = ec2.CfnVPNConnection(
137+
self,
138+
f"NoaaVpnConnection{site}",
139+
customer_gateway_id=cgw.ref,
140+
transit_gateway_id=transit_gateway_id,
141+
type="ipsec.1",
142+
static_routes_only=False,
143+
vpn_tunnel_options_specifications=[tunnel, tunnel],
144+
)

sds_data_manager/constructs/processing_construct.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,11 +138,15 @@ def add_job(self, job_name: str, data_access_url: str = ""):
138138
# fargate_cpu_architecture=ecs.CpuArchitecture.ARM64,
139139
# fargate_operating_system_family=ecs.OperatingSystemFamily.LINUX
140140
)
141-
141+
# Mag l1d jobs need a longer timeout
142+
if "mag" in job_name:
143+
timeout = cdk.Duration.hours(4)
144+
else:
145+
timeout = cdk.Duration.hours(3)
142146
batch.EcsJobDefinition(
143147
self,
144148
f"ProcessingJob-{job_name}",
145149
job_definition_name=f"ProcessingJob-{job_name}",
146150
container=container_definition,
147-
timeout=cdk.Duration.hours(3),
151+
timeout=timeout,
148152
)

sds_data_manager/lambda_code/SDSCode/api_lambdas/latest_version_query.py

Lines changed: 0 additions & 53 deletions
This file was deleted.

sds_data_manager/lambda_code/SDSCode/api_lambdas/query_api.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@
77

88
from sqlalchemy import func, select
99

10-
from ..api_lambdas.utils import is_authenticated_user
11-
from ..api_lambdas.latest_version_query import build_latest_version_query
10+
from ..api_lambdas.utils import build_latest_version_query, is_authenticated_user
1211
from ..database import database as db
1312
from ..database import models
1413

0 commit comments

Comments
 (0)