Proxylity

Now Available: CDK Constructs for UDP Gateway

By Lee Harding | October 18, 2026 | 7 min read
UDP Gateway CDK constructs: L2 composition builds on L1 CloudFormation resources

We've published AWS CDK constructs for Proxylity UDP Gateway. Both the low-level L1 resources and higher-level L2 constructs are available now on npm, PyPI, and NuGet. The source is public at github.com/proxylity/cdk-udp-gateway.

If your application infrastructure already lives in a CDK app, your UDP endpoints can now live there too. Pass a Lambda function or SQS queue to a destination, choose a listener protocol, and let the constructs handle the repetitive wiring. No separate template to keep in sync with the rest of your application.

Why CDK, and why now?

We put Infrastructure-as-Code first when building UDP Gateway. That wasn't a temporary substitute for a click-ops console. We wanted listeners, destinations, permissions, and application code to travel together through version control, code review, and deployment. It makes us more productive, and we know it does the same for our customers.

CloudFormation gave us a solid foundation. It gave us a place to learn what the resource model needed to be before wrapping it in a more opinionated API.

UDP Gateway has grown beyond its original UDP-to-Lambda path: more destination services, encrypted protocols, packet filtering, and server-initiated delivery. As that surface has grown and the underlying resource model has settled, the repeated patterns have become clearer. Creating a destination role, getting its trust relationship right, resolving account configuration, and ordering dependencies are important. Writing them again for every listener isn't where a developer's attention should go.

And that's the timing. A higher-level library is useful when it captures established patterns, already commonly used. Our CDK constructs make such configurations easier without inventing a second model of how UDP Gateway works. The service's growing maturity is the foundation for this release; but the construct library itself is new, and the 0.2 API should not be mistaken for a promise of a frozen interface. We will continue to adapt it as the service and best practices evolve.

A short introduction to CDK

The AWS Cloud Development Kit lets you define infrastructure in a programming language rather than defining resources in YAML or JSON. A CDK app contains stacks, and stacks contain constructs, which are reusable building blocks for infrastructure.

CDK synthesizes those definitions into a CloudFormation template. CloudFormation still handles deployment and resource lifecycle. You're changing how you author the infrastructure, not replacing the deployment engine with a script that creates resources one at a time.

The distinction between construct levels:

We're providing both. You don't have to choose between convenience and access to the underlying resources.

Install it in your language

Use the package for your existing CDK v2 application:

TypeScript / JavaScript (npm)

npm install @proxylity/cdk-udp-gateway

Python (PyPI)

pip install proxylity-cdk-udp-gateway

C# / .NET (NuGet)

dotnet add package Proxylity.CDK.UdpGateway

The TypeScript package uses aws-cdk-lib v2 (at least 2.160.0) and constructs v10. Python imports use proxylity_cdk_udp_gateway; the .NET namespace is Proxylity.CDK.UdpGateway. The language packages are generated from the same library using jsii, rather than maintained as three independent implementations.

A listener alongside your Lambda function

Here's a complete TypeScript stack for an existing CDK app. It creates a Lambda function and a UDP listener that delivers packets to it. Supply your client's public IP as a /32 CIDR (or use IPv6), or a network you control, through the deployment parameter.

import { App, CfnOutput, CfnParameter, Stack, StackProps } from 'aws-cdk-lib';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import { Construct } from 'constructs';
import {
  LambdaDestination,
  Listener,
  ListenerProtocol,
} from '@proxylity/cdk-udp-gateway';

class UdpStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    const clientCidr = new CfnParameter(this, 'ClientCidr', {
      type: 'String',
      description: 'Allowed client public IP/CIDR, for example 203.0.113.10/32',
    });

    const handler = new lambda.Function(this, 'PacketHandler', {
      runtime: new lambda.Runtime('nodejs22.x', lambda.RuntimeFamily.NODEJS, {
        supportsInlineCode: true,
      }),
      handler: 'index.handler',
      code: lambda.Code.fromInline(`
        exports.handler = async (event) => {
          console.log(JSON.stringify(event));
          return { Replies: [] };
        };
      `),
    });

    const listener = new Listener(this, 'UdpListener', {
      protocol: ListenerProtocol.udp(),
      clientRestrictions: { networks: [clientCidr.valueAsString] },
      destinations: [new LambdaDestination({ fn: handler })],
    });

    new CfnOutput(this, 'Endpoint', { value: listener.endpoint });
  }
}

const app = new App();
new UdpStack(app, 'UdpGatewayDemo');

The handler logs the delivered event and sends no replies. It's a starting point for inspecting the packet format, not a finished protocol implementation. Replace it with your application handler when you're ready.

Before deploying, subscribe and connect your AWS account to UDP Gateway. Use the credentials and supported region for that account, and bootstrap your CDK environment if you haven't already. From your CDK app, review and deploy:

npx cdk synth
npx cdk diff
npx cdk deploy --parameters ClientCidr=YOUR_PUBLIC_IP/32

Replace YOUR_PUBLIC_IP with your actual public IP address. There is deliberately no open-to-the-world default: Omitting client restrictions does not admit all traffic. The Endpoint stack output contains the allocated hostname and port after deployment.

Less plumbing, not a different service

The exciting part of that example is what's missing. Listener resolves the stack's Proxylity configuration. LambdaDestination creates a destination role that trusts the Proxylity service role, grants invocation access to the function, and supplies the dependencies so the listener isn't created before its permissions.

We aligned with CDK idioms:

The library also includes packet-source constructs for SNS-driven, server-initiated delivery and regional ARN registration for multi-region destination wiring. Multi-region design still needs explicit decisions about where your destination resources live; a construct doesn't make those architectural choices disappear.

L1 when you want control

The L1 layer provides CfnListener, CfnDestinationArn, and CfnPacketSource. ProxylityConfig.forStack() supplies the shared account/region mapping once per stack. Destinations are configured inline on the listener; there isn't a standalone CfnDestination resource.

For example, inside a stack with the handler and clientCidr from above, this is the lower-level alternative to the L2 listener. Add these imports and use this instead of the new Listener(...) block and its endpoint output:

import * as iam from 'aws-cdk-lib/aws-iam';
import { CfnListener, ProxylityConfig } from '@proxylity/cdk-udp-gateway';

const config = ProxylityConfig.forStack(this);
const role = new iam.Role(this, 'DestinationRole', {
  assumedBy: new iam.ArnPrincipal(config.serviceRole()),
});
const invokeGrant = handler.grantInvoke(role);

const listener = new CfnListener(this, 'UdpListener', {
  serviceToken: config.serviceToken(),
  apiKey: config.apiKey(),
  protocols: ['udp'],
  clientRestrictions: { networks: [clientCidr.valueAsString] },
  destinations: [{
    destinationArn: handler.functionArn,
    role: { arn: role.roleArn },
  }],
});
invokeGrant.applyBefore(listener.resource);

new CfnOutput(this, 'Endpoint', {
  value: `${listener.attrDomain}.proxylity.com:${listener.attrPort}`,
});

With L1, use listener.attrDomain (the subdomain) and listener.attrPort to form <domain>.proxylity.com:<port>. Those values are deployment-time tokens, not values available while your CDK app runs.

L1 keeps close to the service contract and leaves most validation to the resource at deployment. L2 adds typed selections and checks for common invalid combinations. That separation is intentional: convenience shouldn't prevent an advanced configuration the service supports.

Part of the developer toolbox

CDK is another way in, not a requirement to migrate. Plain CloudFormation and SAM remain first-class options, and the Terraform module is there for teams already using Terraform. The CDK constructs fit teams whose application infrastructure is already expressed as code in CDK.

For application code, our examples repository provides working templates and handlers, while the .NET Lambda SDK and .NET project templates help with the packet-handling side. Our Agent Skills package gives AI coding tools UDP Gateway-specific guidance. These solve different parts of the same problem: spending less time on setup and more time on what your service actually does.

The construct library is open source under Apache-2.0. Try it in a stack, inspect the synthesized template, and tell us where the API can better match the way you build. Issues and pull requests are welcome in the public repository.

Bring your UDP endpoint into your CDK app.

Install the constructs, define a listener, and deploy it alongside your application.

Get the CDK Constructs Start with UDP Gateway