Configure AWS Glue Connections

The aws:glue/connection:Connection resource, part of the Pulumi AWS provider, stores connection metadata for Glue jobs to access databases, data warehouses, and other data sources. This guide focuses on four capabilities: JDBC database connections with inline and secret-based credentials, VPC networking for private database access, custom connectors for specialized databases, and cloud data warehouse and search service integration.

Connections reference Secrets Manager secrets, VPC infrastructure, and external data sources that must exist separately. The examples are intentionally small. Combine them with your own VPC configuration, secrets, and data sources.

Connect to a JDBC database with inline credentials

ETL jobs often need to read from or write to relational databases. Glue connections store JDBC URLs and credentials so jobs can access databases without embedding connection details in job code.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const example = new aws.glue.Connection("example", {
    name: "example",
    connectionProperties: {
        JDBC_CONNECTION_URL: "jdbc:mysql://example.com/exampledatabase",
        PASSWORD: "examplepassword",
        USERNAME: "exampleusername",
    },
});
import pulumi
import pulumi_aws as aws

example = aws.glue.Connection("example",
    name="example",
    connection_properties={
        "JDBC_CONNECTION_URL": "jdbc:mysql://example.com/exampledatabase",
        "PASSWORD": "examplepassword",
        "USERNAME": "exampleusername",
    })
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/glue"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := glue.NewConnection(ctx, "example", &glue.ConnectionArgs{
			Name: pulumi.String("example"),
			ConnectionProperties: pulumi.StringMap{
				"JDBC_CONNECTION_URL": pulumi.String("jdbc:mysql://example.com/exampledatabase"),
				"PASSWORD":            pulumi.String("examplepassword"),
				"USERNAME":            pulumi.String("exampleusername"),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var example = new Aws.Glue.Connection("example", new()
    {
        Name = "example",
        ConnectionProperties = 
        {
            { "JDBC_CONNECTION_URL", "jdbc:mysql://example.com/exampledatabase" },
            { "PASSWORD", "examplepassword" },
            { "USERNAME", "exampleusername" },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.glue.Connection;
import com.pulumi.aws.glue.ConnectionArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var example = new Connection("example", ConnectionArgs.builder()
            .name("example")
            .connectionProperties(Map.ofEntries(
                Map.entry("JDBC_CONNECTION_URL", "jdbc:mysql://example.com/exampledatabase"),
                Map.entry("PASSWORD", "examplepassword"),
                Map.entry("USERNAME", "exampleusername")
            ))
            .build());

    }
}
resources:
  example:
    type: aws:glue:Connection
    properties:
      name: example
      connectionProperties:
        JDBC_CONNECTION_URL: jdbc:mysql://example.com/exampledatabase
        PASSWORD: examplepassword
        USERNAME: exampleusername

The connectionProperties map holds the JDBC URL, username, and password. Glue jobs reference this connection by name to access the database. The JDBC_CONNECTION_URL specifies the database endpoint and database name; USERNAME and PASSWORD provide authentication.

Reference credentials from Secrets Manager

Production deployments avoid hardcoding credentials by storing them in Secrets Manager and referencing the secret from the connection.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const example = aws.secretsmanager.getSecret({
    name: "example-secret",
});
const exampleConnection = new aws.glue.Connection("example", {
    name: "example",
    connectionProperties: {
        JDBC_CONNECTION_URL: "jdbc:mysql://example.com/exampledatabase",
        SECRET_ID: example.then(example => example.name),
    },
});
import pulumi
import pulumi_aws as aws

example = aws.secretsmanager.get_secret(name="example-secret")
example_connection = aws.glue.Connection("example",
    name="example",
    connection_properties={
        "JDBC_CONNECTION_URL": "jdbc:mysql://example.com/exampledatabase",
        "SECRET_ID": example.name,
    })
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/glue"
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/secretsmanager"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		example, err := secretsmanager.LookupSecret(ctx, &secretsmanager.LookupSecretArgs{
			Name: pulumi.StringRef("example-secret"),
		}, nil)
		if err != nil {
			return err
		}
		_, err = glue.NewConnection(ctx, "example", &glue.ConnectionArgs{
			Name: pulumi.String("example"),
			ConnectionProperties: pulumi.StringMap{
				"JDBC_CONNECTION_URL": pulumi.String("jdbc:mysql://example.com/exampledatabase"),
				"SECRET_ID":           pulumi.String(example.Name),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var example = Aws.SecretsManager.GetSecret.Invoke(new()
    {
        Name = "example-secret",
    });

    var exampleConnection = new Aws.Glue.Connection("example", new()
    {
        Name = "example",
        ConnectionProperties = 
        {
            { "JDBC_CONNECTION_URL", "jdbc:mysql://example.com/exampledatabase" },
            { "SECRET_ID", example.Apply(getSecretResult => getSecretResult.Name) },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.secretsmanager.SecretsmanagerFunctions;
import com.pulumi.aws.secretsmanager.inputs.GetSecretArgs;
import com.pulumi.aws.glue.Connection;
import com.pulumi.aws.glue.ConnectionArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        final var example = SecretsmanagerFunctions.getSecret(GetSecretArgs.builder()
            .name("example-secret")
            .build());

        var exampleConnection = new Connection("exampleConnection", ConnectionArgs.builder()
            .name("example")
            .connectionProperties(Map.ofEntries(
                Map.entry("JDBC_CONNECTION_URL", "jdbc:mysql://example.com/exampledatabase"),
                Map.entry("SECRET_ID", example.name())
            ))
            .build());

    }
}
resources:
  exampleConnection:
    type: aws:glue:Connection
    name: example
    properties:
      name: example
      connectionProperties:
        JDBC_CONNECTION_URL: jdbc:mysql://example.com/exampledatabase
        SECRET_ID: ${example.name}
variables:
  example:
    fn::invoke:
      function: aws:secretsmanager:getSecret
      arguments:
        name: example-secret

Instead of USERNAME and PASSWORD properties, the SECRET_ID property points to a Secrets Manager secret containing credentials. Glue retrieves credentials at runtime, keeping them out of connection metadata. This extends the basic JDBC pattern with secure credential management.

Connect to databases in private VPC subnets

RDS instances and other databases often run in private subnets without public endpoints. VPC connections allow Glue jobs to reach these resources through elastic network interfaces.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const example = new aws.glue.Connection("example", {
    name: "example",
    connectionProperties: {
        JDBC_CONNECTION_URL: `jdbc:mysql://${exampleAwsRdsCluster.endpoint}/exampledatabase`,
        PASSWORD: "examplepassword",
        USERNAME: "exampleusername",
    },
    physicalConnectionRequirements: {
        availabilityZone: exampleAwsSubnet.availabilityZone,
        securityGroupIdLists: [exampleAwsSecurityGroup.id],
        subnetId: exampleAwsSubnet.id,
    },
});
import pulumi
import pulumi_aws as aws

example = aws.glue.Connection("example",
    name="example",
    connection_properties={
        "JDBC_CONNECTION_URL": f"jdbc:mysql://{example_aws_rds_cluster['endpoint']}/exampledatabase",
        "PASSWORD": "examplepassword",
        "USERNAME": "exampleusername",
    },
    physical_connection_requirements={
        "availability_zone": example_aws_subnet["availabilityZone"],
        "security_group_id_lists": [example_aws_security_group["id"]],
        "subnet_id": example_aws_subnet["id"],
    })
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/glue"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := glue.NewConnection(ctx, "example", &glue.ConnectionArgs{
			Name: pulumi.String("example"),
			ConnectionProperties: pulumi.StringMap{
				"JDBC_CONNECTION_URL": pulumi.Sprintf("jdbc:mysql://%v/exampledatabase", exampleAwsRdsCluster.Endpoint),
				"PASSWORD":            pulumi.String("examplepassword"),
				"USERNAME":            pulumi.String("exampleusername"),
			},
			PhysicalConnectionRequirements: &glue.ConnectionPhysicalConnectionRequirementsArgs{
				AvailabilityZone: pulumi.Any(exampleAwsSubnet.AvailabilityZone),
				SecurityGroupIdLists: pulumi.StringArray{
					exampleAwsSecurityGroup.Id,
				},
				SubnetId: pulumi.Any(exampleAwsSubnet.Id),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var example = new Aws.Glue.Connection("example", new()
    {
        Name = "example",
        ConnectionProperties = 
        {
            { "JDBC_CONNECTION_URL", $"jdbc:mysql://{exampleAwsRdsCluster.Endpoint}/exampledatabase" },
            { "PASSWORD", "examplepassword" },
            { "USERNAME", "exampleusername" },
        },
        PhysicalConnectionRequirements = new Aws.Glue.Inputs.ConnectionPhysicalConnectionRequirementsArgs
        {
            AvailabilityZone = exampleAwsSubnet.AvailabilityZone,
            SecurityGroupIdLists = new[]
            {
                exampleAwsSecurityGroup.Id,
            },
            SubnetId = exampleAwsSubnet.Id,
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.glue.Connection;
import com.pulumi.aws.glue.ConnectionArgs;
import com.pulumi.aws.glue.inputs.ConnectionPhysicalConnectionRequirementsArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var example = new Connection("example", ConnectionArgs.builder()
            .name("example")
            .connectionProperties(Map.ofEntries(
                Map.entry("JDBC_CONNECTION_URL", String.format("jdbc:mysql://%s/exampledatabase", exampleAwsRdsCluster.endpoint())),
                Map.entry("PASSWORD", "examplepassword"),
                Map.entry("USERNAME", "exampleusername")
            ))
            .physicalConnectionRequirements(ConnectionPhysicalConnectionRequirementsArgs.builder()
                .availabilityZone(exampleAwsSubnet.availabilityZone())
                .securityGroupIdLists(exampleAwsSecurityGroup.id())
                .subnetId(exampleAwsSubnet.id())
                .build())
            .build());

    }
}
resources:
  example:
    type: aws:glue:Connection
    properties:
      name: example
      connectionProperties:
        JDBC_CONNECTION_URL: jdbc:mysql://${exampleAwsRdsCluster.endpoint}/exampledatabase
        PASSWORD: examplepassword
        USERNAME: exampleusername
      physicalConnectionRequirements:
        availabilityZone: ${exampleAwsSubnet.availabilityZone}
        securityGroupIdLists:
          - ${exampleAwsSecurityGroup.id}
        subnetId: ${exampleAwsSubnet.id}

The physicalConnectionRequirements block places Glue’s network interface in your subnet with specified security groups. The subnetId determines which subnet hosts the interface; securityGroupIdLists controls network access rules. Glue creates and manages the network interface automatically when jobs use this connection.

Define and use custom JDBC connectors

Glue supports custom connectors for databases not covered by built-in connection types. Teams define a template connection with the connector JAR location, then reference it from actual connections.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

// Define the custom connector using the connection_type of `CUSTOM` with the match_criteria of `template_connection`
// Example here being a snowflake jdbc connector with a secret having user and password as keys
const example = aws.secretsmanager.getSecret({
    name: "example-secret",
});
const example1 = new aws.glue.Connection("example1", {
    name: "example1",
    connectionType: "CUSTOM",
    connectionProperties: {
        CONNECTOR_CLASS_NAME: "net.snowflake.client.jdbc.SnowflakeDriver",
        CONNECTION_TYPE: "Jdbc",
        CONNECTOR_URL: "s3://example/snowflake-jdbc.jar",
        JDBC_CONNECTION_URL: "[[\"default=jdbc:snowflake://example.com/?user=${user}&password=${password}\"],\",\"]",
    },
    matchCriterias: ["template-connection"],
});
// Reference the connector using match_criteria with the connector created above.
const example2 = new aws.glue.Connection("example2", {
    name: "example2",
    connectionType: "CUSTOM",
    connectionProperties: {
        CONNECTOR_CLASS_NAME: "net.snowflake.client.jdbc.SnowflakeDriver",
        CONNECTION_TYPE: "Jdbc",
        CONNECTOR_URL: "s3://example/snowflake-jdbc.jar",
        JDBC_CONNECTION_URL: "jdbc:snowflake://example.com/?user=${user}&password=${password}",
        SECRET_ID: example.then(example => example.name),
    },
    matchCriterias: [
        "Connection",
        example1.name,
    ],
});
import pulumi
import pulumi_aws as aws

# Define the custom connector using the connection_type of `CUSTOM` with the match_criteria of `template_connection`
# Example here being a snowflake jdbc connector with a secret having user and password as keys
example = aws.secretsmanager.get_secret(name="example-secret")
example1 = aws.glue.Connection("example1",
    name="example1",
    connection_type="CUSTOM",
    connection_properties={
        "CONNECTOR_CLASS_NAME": "net.snowflake.client.jdbc.SnowflakeDriver",
        "CONNECTION_TYPE": "Jdbc",
        "CONNECTOR_URL": "s3://example/snowflake-jdbc.jar",
        "JDBC_CONNECTION_URL": "[[\"default=jdbc:snowflake://example.com/?user=${user}&password=${password}\"],\",\"]",
    },
    match_criterias=["template-connection"])
# Reference the connector using match_criteria with the connector created above.
example2 = aws.glue.Connection("example2",
    name="example2",
    connection_type="CUSTOM",
    connection_properties={
        "CONNECTOR_CLASS_NAME": "net.snowflake.client.jdbc.SnowflakeDriver",
        "CONNECTION_TYPE": "Jdbc",
        "CONNECTOR_URL": "s3://example/snowflake-jdbc.jar",
        "JDBC_CONNECTION_URL": "jdbc:snowflake://example.com/?user=${user}&password=${password}",
        "SECRET_ID": example.name,
    },
    match_criterias=[
        "Connection",
        example1.name,
    ])
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/glue"
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/secretsmanager"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		// Define the custom connector using the connection_type of `CUSTOM` with the match_criteria of `template_connection`
		// Example here being a snowflake jdbc connector with a secret having user and password as keys
		example, err := secretsmanager.LookupSecret(ctx, &secretsmanager.LookupSecretArgs{
			Name: pulumi.StringRef("example-secret"),
		}, nil)
		if err != nil {
			return err
		}
		example1, err := glue.NewConnection(ctx, "example1", &glue.ConnectionArgs{
			Name:           pulumi.String("example1"),
			ConnectionType: pulumi.String("CUSTOM"),
			ConnectionProperties: pulumi.StringMap{
				"CONNECTOR_CLASS_NAME": pulumi.String("net.snowflake.client.jdbc.SnowflakeDriver"),
				"CONNECTION_TYPE":      pulumi.String("Jdbc"),
				"CONNECTOR_URL":        pulumi.String("s3://example/snowflake-jdbc.jar"),
				"JDBC_CONNECTION_URL":  pulumi.String("[[\"default=jdbc:snowflake://example.com/?user=${user}&password=${password}\"],\",\"]"),
			},
			MatchCriterias: pulumi.StringArray{
				pulumi.String("template-connection"),
			},
		})
		if err != nil {
			return err
		}
		// Reference the connector using match_criteria with the connector created above.
		_, err = glue.NewConnection(ctx, "example2", &glue.ConnectionArgs{
			Name:           pulumi.String("example2"),
			ConnectionType: pulumi.String("CUSTOM"),
			ConnectionProperties: pulumi.StringMap{
				"CONNECTOR_CLASS_NAME": pulumi.String("net.snowflake.client.jdbc.SnowflakeDriver"),
				"CONNECTION_TYPE":      pulumi.String("Jdbc"),
				"CONNECTOR_URL":        pulumi.String("s3://example/snowflake-jdbc.jar"),
				"JDBC_CONNECTION_URL":  pulumi.String("jdbc:snowflake://example.com/?user=${user}&password=${password}"),
				"SECRET_ID":            pulumi.String(example.Name),
			},
			MatchCriterias: pulumi.StringArray{
				pulumi.String("Connection"),
				example1.Name,
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    // Define the custom connector using the connection_type of `CUSTOM` with the match_criteria of `template_connection`
    // Example here being a snowflake jdbc connector with a secret having user and password as keys
    var example = Aws.SecretsManager.GetSecret.Invoke(new()
    {
        Name = "example-secret",
    });

    var example1 = new Aws.Glue.Connection("example1", new()
    {
        Name = "example1",
        ConnectionType = "CUSTOM",
        ConnectionProperties = 
        {
            { "CONNECTOR_CLASS_NAME", "net.snowflake.client.jdbc.SnowflakeDriver" },
            { "CONNECTION_TYPE", "Jdbc" },
            { "CONNECTOR_URL", "s3://example/snowflake-jdbc.jar" },
            { "JDBC_CONNECTION_URL", "[[\"default=jdbc:snowflake://example.com/?user=${user}&password=${password}\"],\",\"]" },
        },
        MatchCriterias = new[]
        {
            "template-connection",
        },
    });

    // Reference the connector using match_criteria with the connector created above.
    var example2 = new Aws.Glue.Connection("example2", new()
    {
        Name = "example2",
        ConnectionType = "CUSTOM",
        ConnectionProperties = 
        {
            { "CONNECTOR_CLASS_NAME", "net.snowflake.client.jdbc.SnowflakeDriver" },
            { "CONNECTION_TYPE", "Jdbc" },
            { "CONNECTOR_URL", "s3://example/snowflake-jdbc.jar" },
            { "JDBC_CONNECTION_URL", "jdbc:snowflake://example.com/?user=${user}&password=${password}" },
            { "SECRET_ID", example.Apply(getSecretResult => getSecretResult.Name) },
        },
        MatchCriterias = new[]
        {
            "Connection",
            example1.Name,
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.secretsmanager.SecretsmanagerFunctions;
import com.pulumi.aws.secretsmanager.inputs.GetSecretArgs;
import com.pulumi.aws.glue.Connection;
import com.pulumi.aws.glue.ConnectionArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        // Define the custom connector using the connection_type of `CUSTOM` with the match_criteria of `template_connection`
        // Example here being a snowflake jdbc connector with a secret having user and password as keys
        final var example = SecretsmanagerFunctions.getSecret(GetSecretArgs.builder()
            .name("example-secret")
            .build());

        var example1 = new Connection("example1", ConnectionArgs.builder()
            .name("example1")
            .connectionType("CUSTOM")
            .connectionProperties(Map.ofEntries(
                Map.entry("CONNECTOR_CLASS_NAME", "net.snowflake.client.jdbc.SnowflakeDriver"),
                Map.entry("CONNECTION_TYPE", "Jdbc"),
                Map.entry("CONNECTOR_URL", "s3://example/snowflake-jdbc.jar"),
                Map.entry("JDBC_CONNECTION_URL", "[[\"default=jdbc:snowflake://example.com/?user=${user}&password=${password}\"],\",\"]")
            ))
            .matchCriterias("template-connection")
            .build());

        // Reference the connector using match_criteria with the connector created above.
        var example2 = new Connection("example2", ConnectionArgs.builder()
            .name("example2")
            .connectionType("CUSTOM")
            .connectionProperties(Map.ofEntries(
                Map.entry("CONNECTOR_CLASS_NAME", "net.snowflake.client.jdbc.SnowflakeDriver"),
                Map.entry("CONNECTION_TYPE", "Jdbc"),
                Map.entry("CONNECTOR_URL", "s3://example/snowflake-jdbc.jar"),
                Map.entry("JDBC_CONNECTION_URL", "jdbc:snowflake://example.com/?user=${user}&password=${password}"),
                Map.entry("SECRET_ID", example.name())
            ))
            .matchCriterias(            
                "Connection",
                example1.name())
            .build());

    }
}
resources:
  example1:
    type: aws:glue:Connection
    properties:
      name: example1
      connectionType: CUSTOM
      connectionProperties:
        CONNECTOR_CLASS_NAME: net.snowflake.client.jdbc.SnowflakeDriver
        CONNECTION_TYPE: Jdbc
        CONNECTOR_URL: s3://example/snowflake-jdbc.jar
        JDBC_CONNECTION_URL: '[["default=jdbc:snowflake://example.com/?user=$${user}&password=$${password}"],","]'
      matchCriterias:
        - template-connection
  # Reference the connector using match_criteria with the connector created above.
  example2:
    type: aws:glue:Connection
    properties:
      name: example2
      connectionType: CUSTOM
      connectionProperties:
        CONNECTOR_CLASS_NAME: net.snowflake.client.jdbc.SnowflakeDriver
        CONNECTION_TYPE: Jdbc
        CONNECTOR_URL: s3://example/snowflake-jdbc.jar
        JDBC_CONNECTION_URL: jdbc:snowflake://example.com/?user=$${user}&password=$${password}
        SECRET_ID: ${example.name}
      matchCriterias:
        - Connection
        - ${example1.name}
variables:
  # Define the custom connector using the connection_type of `CUSTOM` with the match_criteria of `template_connection`
  # Example here being a snowflake jdbc connector with a secret having user and password as keys
  example:
    fn::invoke:
      function: aws:secretsmanager:getSecret
      arguments:
        name: example-secret

The first connection (example1) acts as a template with connectionType set to CUSTOM and matchCriterias containing “template-connection”. It specifies the CONNECTOR_CLASS_NAME (JDBC driver class), CONNECTOR_URL (S3 path to JAR), and a parameterized JDBC_CONNECTION_URL. The second connection (example2) references the template via matchCriterias and provides actual credentials through SECRET_ID.

Connect to OpenSearch for search and analytics

Data pipelines that need to query or index documents in OpenSearch use Spark-based connections with authentication and endpoint configuration.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const example = new aws.secretsmanager.Secret("example", {name: "example-secret"});
const exampleSecretVersion = new aws.secretsmanager.SecretVersion("example", {
    secretId: example.id,
    secretString: JSON.stringify({
        "opensearch.net.http.auth.user": "exampleusername",
        "opensearch.net.http.auth.pass": "examplepassword",
    }),
});
const exampleConnection = new aws.glue.Connection("example", {
    name: "example",
    connectionType: "OPENSEARCH",
    connectionProperties: {
        SparkProperties: pulumi.jsonStringify({
            secretId: example.name,
            "opensearch.nodes": "https://search-exampledomain-ixlmh4jieahrau3bfebcgp8cnm.us-east-1.es.amazonaws.com",
            "opensearch.port": "443",
            "opensearch.aws.sigv4.region": "us-east-1",
            "opensearch.nodes.wan.only": "true",
            "opensearch.aws.sigv4.enabled": "true",
        }),
    },
});
import pulumi
import json
import pulumi_aws as aws

example = aws.secretsmanager.Secret("example", name="example-secret")
example_secret_version = aws.secretsmanager.SecretVersion("example",
    secret_id=example.id,
    secret_string=json.dumps({
        "opensearch.net.http.auth.user": "exampleusername",
        "opensearch.net.http.auth.pass": "examplepassword",
    }))
example_connection = aws.glue.Connection("example",
    name="example",
    connection_type="OPENSEARCH",
    connection_properties={
        "SparkProperties": pulumi.Output.json_dumps({
            "secretId": example.name,
            "opensearch.nodes": "https://search-exampledomain-ixlmh4jieahrau3bfebcgp8cnm.us-east-1.es.amazonaws.com",
            "opensearch.port": "443",
            "opensearch.aws.sigv4.region": "us-east-1",
            "opensearch.nodes.wan.only": "true",
            "opensearch.aws.sigv4.enabled": "true",
        }),
    })
package main

import (
	"encoding/json"

	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/glue"
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/secretsmanager"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		example, err := secretsmanager.NewSecret(ctx, "example", &secretsmanager.SecretArgs{
			Name: pulumi.String("example-secret"),
		})
		if err != nil {
			return err
		}
		tmpJSON0, err := json.Marshal(map[string]interface{}{
			"opensearch.net.http.auth.user": "exampleusername",
			"opensearch.net.http.auth.pass": "examplepassword",
		})
		if err != nil {
			return err
		}
		json0 := string(tmpJSON0)
		_, err = secretsmanager.NewSecretVersion(ctx, "example", &secretsmanager.SecretVersionArgs{
			SecretId:     example.ID(),
			SecretString: pulumi.String(json0),
		})
		if err != nil {
			return err
		}
		_, err = glue.NewConnection(ctx, "example", &glue.ConnectionArgs{
			Name:           pulumi.String("example"),
			ConnectionType: pulumi.String("OPENSEARCH"),
			ConnectionProperties: pulumi.StringMap{
				"SparkProperties": example.Name.ApplyT(func(name string) (pulumi.String, error) {
					var _zero pulumi.String
					tmpJSON1, err := json.Marshal(map[string]interface{}{
						"secretId":                     name,
						"opensearch.nodes":             "https://search-exampledomain-ixlmh4jieahrau3bfebcgp8cnm.us-east-1.es.amazonaws.com",
						"opensearch.port":              "443",
						"opensearch.aws.sigv4.region":  "us-east-1",
						"opensearch.nodes.wan.only":    "true",
						"opensearch.aws.sigv4.enabled": "true",
					})
					if err != nil {
						return _zero, err
					}
					json1 := string(tmpJSON1)
					return pulumi.String(json1), nil
				}).(pulumi.StringOutput),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var example = new Aws.SecretsManager.Secret("example", new()
    {
        Name = "example-secret",
    });

    var exampleSecretVersion = new Aws.SecretsManager.SecretVersion("example", new()
    {
        SecretId = example.Id,
        SecretString = JsonSerializer.Serialize(new Dictionary<string, object?>
        {
            ["opensearch.net.http.auth.user"] = "exampleusername",
            ["opensearch.net.http.auth.pass"] = "examplepassword",
        }),
    });

    var exampleConnection = new Aws.Glue.Connection("example", new()
    {
        Name = "example",
        ConnectionType = "OPENSEARCH",
        ConnectionProperties = 
        {
            { "SparkProperties", Output.JsonSerialize(Output.Create(new Dictionary<string, object?>
            {
                ["secretId"] = example.Name,
                ["opensearch.nodes"] = "https://search-exampledomain-ixlmh4jieahrau3bfebcgp8cnm.us-east-1.es.amazonaws.com",
                ["opensearch.port"] = "443",
                ["opensearch.aws.sigv4.region"] = "us-east-1",
                ["opensearch.nodes.wan.only"] = "true",
                ["opensearch.aws.sigv4.enabled"] = "true",
            })) },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.secretsmanager.Secret;
import com.pulumi.aws.secretsmanager.SecretArgs;
import com.pulumi.aws.secretsmanager.SecretVersion;
import com.pulumi.aws.secretsmanager.SecretVersionArgs;
import com.pulumi.aws.glue.Connection;
import com.pulumi.aws.glue.ConnectionArgs;
import static com.pulumi.codegen.internal.Serialization.*;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var example = new Secret("example", SecretArgs.builder()
            .name("example-secret")
            .build());

        var exampleSecretVersion = new SecretVersion("exampleSecretVersion", SecretVersionArgs.builder()
            .secretId(example.id())
            .secretString(serializeJson(
                jsonObject(
                    jsonProperty("opensearch.net.http.auth.user", "exampleusername"),
                    jsonProperty("opensearch.net.http.auth.pass", "examplepassword")
                )))
            .build());

        var exampleConnection = new Connection("exampleConnection", ConnectionArgs.builder()
            .name("example")
            .connectionType("OPENSEARCH")
            .connectionProperties(Map.of("SparkProperties", example.name().applyValue(_name -> serializeJson(
                jsonObject(
                    jsonProperty("secretId", _name),
                    jsonProperty("opensearch.nodes", "https://search-exampledomain-ixlmh4jieahrau3bfebcgp8cnm.us-east-1.es.amazonaws.com"),
                    jsonProperty("opensearch.port", "443"),
                    jsonProperty("opensearch.aws.sigv4.region", "us-east-1"),
                    jsonProperty("opensearch.nodes.wan.only", "true"),
                    jsonProperty("opensearch.aws.sigv4.enabled", "true")
                )))))
            .build());

    }
}
resources:
  example:
    type: aws:secretsmanager:Secret
    properties:
      name: example-secret
  exampleSecretVersion:
    type: aws:secretsmanager:SecretVersion
    name: example
    properties:
      secretId: ${example.id}
      secretString:
        fn::toJSON:
          opensearch.net.http.auth.user: exampleusername
          opensearch.net.http.auth.pass: examplepassword
  exampleConnection:
    type: aws:glue:Connection
    name: example
    properties:
      name: example
      connectionType: OPENSEARCH
      connectionProperties:
        SparkProperties:
          fn::toJSON:
            secretId: ${example.name}
            opensearch.nodes: https://search-exampledomain-ixlmh4jieahrau3bfebcgp8cnm.us-east-1.es.amazonaws.com
            opensearch.port: '443'
            opensearch.aws.sigv4.region: us-east-1
            opensearch.nodes.wan.only: 'true'
            opensearch.aws.sigv4.enabled: 'true'

The connectionType is OPENSEARCH, and SparkProperties contains a JSON document with OpenSearch-specific settings. The opensearch.nodes property specifies the domain endpoint; opensearch.aws.sigv4.enabled enables AWS signature authentication. Credentials come from the referenced Secrets Manager secret.

Connect to Snowflake data warehouses

Analytics teams often load data into Snowflake for querying and reporting. Glue connections to Snowflake use Spark properties with role and URL configuration.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const example = new aws.secretsmanager.Secret("example", {name: "example-secret"});
const exampleSecretVersion = new aws.secretsmanager.SecretVersion("example", {
    secretId: example.id,
    secretString: JSON.stringify({
        sfUser: "exampleusername",
        sfPassword: "examplepassword",
    }),
});
const exampleConnection = new aws.glue.Connection("example", {
    name: "example",
    connectionType: "SNOWFLAKE",
    connectionProperties: {
        SparkProperties: pulumi.jsonStringify({
            secretId: example.name,
            sfRole: "EXAMPLEETLROLE",
            sfUrl: "exampleorg-exampleconnection.snowflakecomputing.com",
        }),
    },
});
import pulumi
import json
import pulumi_aws as aws

example = aws.secretsmanager.Secret("example", name="example-secret")
example_secret_version = aws.secretsmanager.SecretVersion("example",
    secret_id=example.id,
    secret_string=json.dumps({
        "sfUser": "exampleusername",
        "sfPassword": "examplepassword",
    }))
example_connection = aws.glue.Connection("example",
    name="example",
    connection_type="SNOWFLAKE",
    connection_properties={
        "SparkProperties": pulumi.Output.json_dumps({
            "secretId": example.name,
            "sfRole": "EXAMPLEETLROLE",
            "sfUrl": "exampleorg-exampleconnection.snowflakecomputing.com",
        }),
    })
package main

import (
	"encoding/json"

	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/glue"
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/secretsmanager"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		example, err := secretsmanager.NewSecret(ctx, "example", &secretsmanager.SecretArgs{
			Name: pulumi.String("example-secret"),
		})
		if err != nil {
			return err
		}
		tmpJSON0, err := json.Marshal(map[string]interface{}{
			"sfUser":     "exampleusername",
			"sfPassword": "examplepassword",
		})
		if err != nil {
			return err
		}
		json0 := string(tmpJSON0)
		_, err = secretsmanager.NewSecretVersion(ctx, "example", &secretsmanager.SecretVersionArgs{
			SecretId:     example.ID(),
			SecretString: pulumi.String(json0),
		})
		if err != nil {
			return err
		}
		_, err = glue.NewConnection(ctx, "example", &glue.ConnectionArgs{
			Name:           pulumi.String("example"),
			ConnectionType: pulumi.String("SNOWFLAKE"),
			ConnectionProperties: pulumi.StringMap{
				"SparkProperties": example.Name.ApplyT(func(name string) (pulumi.String, error) {
					var _zero pulumi.String
					tmpJSON1, err := json.Marshal(map[string]interface{}{
						"secretId": name,
						"sfRole":   "EXAMPLEETLROLE",
						"sfUrl":    "exampleorg-exampleconnection.snowflakecomputing.com",
					})
					if err != nil {
						return _zero, err
					}
					json1 := string(tmpJSON1)
					return pulumi.String(json1), nil
				}).(pulumi.StringOutput),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var example = new Aws.SecretsManager.Secret("example", new()
    {
        Name = "example-secret",
    });

    var exampleSecretVersion = new Aws.SecretsManager.SecretVersion("example", new()
    {
        SecretId = example.Id,
        SecretString = JsonSerializer.Serialize(new Dictionary<string, object?>
        {
            ["sfUser"] = "exampleusername",
            ["sfPassword"] = "examplepassword",
        }),
    });

    var exampleConnection = new Aws.Glue.Connection("example", new()
    {
        Name = "example",
        ConnectionType = "SNOWFLAKE",
        ConnectionProperties = 
        {
            { "SparkProperties", Output.JsonSerialize(Output.Create(new Dictionary<string, object?>
            {
                ["secretId"] = example.Name,
                ["sfRole"] = "EXAMPLEETLROLE",
                ["sfUrl"] = "exampleorg-exampleconnection.snowflakecomputing.com",
            })) },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.secretsmanager.Secret;
import com.pulumi.aws.secretsmanager.SecretArgs;
import com.pulumi.aws.secretsmanager.SecretVersion;
import com.pulumi.aws.secretsmanager.SecretVersionArgs;
import com.pulumi.aws.glue.Connection;
import com.pulumi.aws.glue.ConnectionArgs;
import static com.pulumi.codegen.internal.Serialization.*;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var example = new Secret("example", SecretArgs.builder()
            .name("example-secret")
            .build());

        var exampleSecretVersion = new SecretVersion("exampleSecretVersion", SecretVersionArgs.builder()
            .secretId(example.id())
            .secretString(serializeJson(
                jsonObject(
                    jsonProperty("sfUser", "exampleusername"),
                    jsonProperty("sfPassword", "examplepassword")
                )))
            .build());

        var exampleConnection = new Connection("exampleConnection", ConnectionArgs.builder()
            .name("example")
            .connectionType("SNOWFLAKE")
            .connectionProperties(Map.of("SparkProperties", example.name().applyValue(_name -> serializeJson(
                jsonObject(
                    jsonProperty("secretId", _name),
                    jsonProperty("sfRole", "EXAMPLEETLROLE"),
                    jsonProperty("sfUrl", "exampleorg-exampleconnection.snowflakecomputing.com")
                )))))
            .build());

    }
}
resources:
  example:
    type: aws:secretsmanager:Secret
    properties:
      name: example-secret
  exampleSecretVersion:
    type: aws:secretsmanager:SecretVersion
    name: example
    properties:
      secretId: ${example.id}
      secretString:
        fn::toJSON:
          sfUser: exampleusername
          sfPassword: examplepassword
  exampleConnection:
    type: aws:glue:Connection
    name: example
    properties:
      name: example
      connectionType: SNOWFLAKE
      connectionProperties:
        SparkProperties:
          fn::toJSON:
            secretId: ${example.name}
            sfRole: EXAMPLEETLROLE
            sfUrl: exampleorg-exampleconnection.snowflakecomputing.com

The connectionType is SNOWFLAKE, and SparkProperties contains Snowflake-specific settings. The sfUrl property specifies the Snowflake account URL; sfRole defines the role Glue assumes when connecting. Credentials (sfUser and sfPassword) are stored in the referenced Secrets Manager secret.

Beyond these examples

These snippets focus on specific connection-level features: JDBC and custom connector configuration, Secrets Manager integration, VPC networking for private resources, and cloud data warehouse and search service connections. They’re intentionally minimal rather than full ETL pipelines.

The examples may reference pre-existing infrastructure such as Secrets Manager secrets with database credentials, VPC subnets and security groups and RDS clusters, S3 buckets for custom connector JARs, and OpenSearch domains and Snowflake accounts. They focus on configuring the connection rather than provisioning everything around it.

To keep things focused, common connection patterns are omitted, including:

  • Kafka and MongoDB connection types
  • Network connection type for VPC peering
  • Athena federated query properties (athenaProperties)
  • Connection validation and testing

These omissions are intentional: the goal is to illustrate how each connection feature is wired, not provide drop-in ETL modules. See the Glue Connection resource reference for all available configuration options.

Let's configure AWS Glue Connections

Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.

Try Pulumi Cloud for FREE

Frequently Asked Questions

Connection Types & Configuration
What connection types are supported?
Glue supports AZURECOSMOS, AZURESQL, BIGQUERY, CUSTOM, DYNAMODB, JDBC, KAFKA, MARKETPLACE, MONGODB, NETWORK, OPENSEARCH, and SNOWFLAKE. The default is JDBC.
Which connection types require SparkProperties?
AZURECOSMOS, AZURESQL, BIGQUERY, OPENSEARCH, and SNOWFLAKE require a SparkProperties key within connectionProperties containing a JSON document. Use pulumi.jsonStringify() to create this JSON.
What's the difference between athenaProperties and connectionProperties?
DynamoDB connections use athenaProperties for Athena-specific settings like lambda_function_arn and spill_bucket, while most other connection types use connectionProperties.
Authentication & Secrets
How do I use AWS Secrets Manager instead of hardcoded passwords?
Set SECRET_ID in connectionProperties to your secret name instead of using PASSWORD and USERNAME keys.
Can I store credentials in Secrets Manager for all connection types?
Yes. Examples show Secrets Manager integration for JDBC, AZURECOSMOS, AZURESQL, BIGQUERY, OPENSEARCH, and SNOWFLAKE connections using either SECRET_ID or secretId within SparkProperties.
VPC & Networking
How do I connect to resources in a VPC?
Configure physicalConnectionRequirements with availabilityZone, securityGroupIdLists, and subnetId properties.
Custom Connectors & Advanced Configuration
How do I create and use a custom connector?
First, create a template connection with connectionType: "CUSTOM" and matchCriterias: ["template-connection"]. Then reference it in other connections using matchCriterias: ["Connection", templateName].
What are matchCriterias used for?
matchCriterias define selection criteria for connections. For custom connectors, use ["template-connection"] to define a template, then ["Connection", templateName] to reference it.
Immutability & Limitations
What properties can't I change after creating a connection?
Both catalogId and name are immutable. Changing either requires replacing the entire connection resource.

Using a different cloud?

Explore analytics guides for other cloud providers: