SDK Configuration

All modern AWS SDKs support the AWS_ENDPOINT_URL environment variable. When running inside Simfra containers (Lambda, ECS, EC2), this is injected automatically. For host applications, set it manually.

Prerequisites

Environment Variables

export AWS_ENDPOINT_URL=http://localhost:4599
export AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
export AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
export AWS_DEFAULT_REGION=us-east-1

With these variables set, SDK code in any language works without modification. This page also shows explicit endpoint configuration for cases where environment variables are not an option.

Go (aws-sdk-go-v2)

Automatic (environment variable)

package main

import (
    "context"
    "github.com/aws/aws-sdk-go-v2/config"
    "github.com/aws/aws-sdk-go-v2/service/s3"
)

func main() {
    ctx := context.Background()

    // Reads AWS_ENDPOINT_URL, AWS_REGION, and credentials from environment
    cfg, err := config.LoadDefaultConfig(ctx)
    if err != nil {
        panic(err)
    }

    client := s3.NewFromConfig(cfg)

    out, err := client.ListBuckets(ctx, &s3.ListBucketsInput{})
    if err != nil {
        panic(err)
    }
    for _, b := range out.Buckets {
        println(*b.Name)
    }
}

Explicit endpoint override

cfg, _ := config.LoadDefaultConfig(ctx,
    config.WithRegion("us-east-1"),
)

client := s3.NewFromConfig(cfg, func(o *s3.Options) {
    o.BaseEndpoint = aws.String("http://localhost:4599")
    o.UsePathStyle = true
})

Per-client endpoint overrides are useful when you need different clients to point at different targets (e.g., one at Simfra, one at real AWS).

Python (boto3)

Automatic (environment variable)

AWS_ENDPOINT_URL is supported in boto3 >= 1.28.57 (September 2023):

import boto3

# Reads AWS_ENDPOINT_URL automatically
s3 = boto3.client('s3')

response = s3.list_buckets()
for bucket in response['Buckets']:
    print(bucket['Name'])

Explicit endpoint override

import boto3

s3 = boto3.client(
    's3',
    endpoint_url='http://localhost:4599',
    region_name='us-east-1',
    aws_access_key_id='AKIAIOSFODNN7EXAMPLE',
    aws_secret_access_key='wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY'
)

dynamodb = boto3.resource(
    'dynamodb',
    endpoint_url='http://localhost:4599',
    region_name='us-east-1'
)

boto3 session

session = boto3.Session(
    region_name='us-east-1',
    aws_access_key_id='AKIAIOSFODNN7EXAMPLE',
    aws_secret_access_key='wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY'
)

# All clients from this session use the same credentials
s3 = session.client('s3', endpoint_url='http://localhost:4599')
sqs = session.client('sqs', endpoint_url='http://localhost:4599')

JavaScript / TypeScript (AWS SDK v3)

Automatic (environment variable)

AWS_ENDPOINT_URL is supported in AWS SDK for JavaScript v3 >= 3.451.0:

import { S3Client, ListBucketsCommand } from '@aws-sdk/client-s3';

// Reads AWS_ENDPOINT_URL automatically
const client = new S3Client({ region: 'us-east-1' });

const { Buckets } = await client.send(new ListBucketsCommand({}));
Buckets?.forEach(b => console.log(b.Name));

Explicit endpoint override

import { S3Client, ListBucketsCommand } from '@aws-sdk/client-s3';

const client = new S3Client({
  endpoint: 'http://localhost:4599',
  region: 'us-east-1',
  credentials: {
    accessKeyId: 'AKIAIOSFODNN7EXAMPLE',
    secretAccessKey: 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY'
  },
  forcePathStyle: true  // Required for S3
});

DynamoDB example

import { DynamoDBClient, PutItemCommand } from '@aws-sdk/client-dynamodb';

const dynamodb = new DynamoDBClient({ region: 'us-east-1' });

await dynamodb.send(new PutItemCommand({
  TableName: 'my-table',
  Item: {
    id: { S: '123' },
    name: { S: 'test' }
  }
}));

Java (AWS SDK v2)

Explicit endpoint override

The Java SDK v2 does not read AWS_ENDPOINT_URL automatically. Configure the endpoint explicitly:

import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;

import java.net.URI;

public class SimfraExample {
    public static void main(String[] args) {
        S3Client s3 = S3Client.builder()
            .endpointOverride(URI.create("http://localhost:4599"))
            .region(Region.US_EAST_1)
            .credentialsProvider(StaticCredentialsProvider.create(
                AwsBasicCredentials.create(
                    "AKIAIOSFODNN7EXAMPLE",
                    "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
                )
            ))
            .forcePathStyle(true)  // Required for S3
            .build();

        s3.listBuckets().buckets().forEach(
            b -> System.out.println(b.name())
        );
    }
}

DynamoDB example

import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.*;

DynamoDbClient dynamodb = DynamoDbClient.builder()
    .endpointOverride(URI.create("http://localhost:4599"))
    .region(Region.US_EAST_1)
    .build();

dynamodb.putItem(PutItemRequest.builder()
    .tableName("my-table")
    .item(Map.of(
        "id", AttributeValue.fromS("123"),
        "name", AttributeValue.fromS("test")
    ))
    .build());

Reusable configuration helper

import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.sqs.SqsClient;

public class SimfraClients {
    private static final URI ENDPOINT = URI.create(
        System.getenv().getOrDefault("AWS_ENDPOINT_URL", "http://localhost:4599")
    );

    public static S3Client s3() {
        return S3Client.builder()
            .endpointOverride(ENDPOINT)
            .region(Region.US_EAST_1)
            .forcePathStyle(true)
            .build();
    }

    public static SqsClient sqs() {
        return SqsClient.builder()
            .endpointOverride(ENDPOINT)
            .region(Region.US_EAST_1)
            .build();
    }
}

.NET (AWS SDK for .NET)

using Amazon;
using Amazon.S3;
using Amazon.Runtime;

var credentials = new BasicAWSCredentials(
    "AKIAIOSFODNN7EXAMPLE",
    "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
);

var config = new AmazonS3Config
{
    ServiceURL = "http://localhost:4599",
    ForcePathStyle = true,
    AuthenticationRegion = "us-east-1"
};

var s3 = new AmazonS3Client(credentials, config);

var response = await s3.ListBucketsAsync();
foreach (var bucket in response.Buckets)
{
    Console.WriteLine(bucket.BucketName);
}

Ruby (AWS SDK v3)

require 'aws-sdk-s3'

# Reads AWS_ENDPOINT_URL automatically (aws-sdk-core >= 3.186.0)
s3 = Aws::S3::Client.new(region: 'us-east-1')

# Or explicit:
s3 = Aws::S3::Client.new(
  endpoint: 'http://localhost:4599',
  region: 'us-east-1',
  access_key_id: 'AKIAIOSFODNN7EXAMPLE',
  secret_access_key: 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY',
  force_path_style: true
)

s3.list_buckets.buckets.each { |b| puts b.name }

S3 Path Style

Simfra runs on localhost, so S3 virtual-hosted-style addressing (bucket.s3.amazonaws.com) does not work. All S3 SDK clients must use path-style addressing:

Language Setting
Go o.UsePathStyle = true
Python Handled automatically by endpoint_url
JavaScript forcePathStyle: true
Java .forcePathStyle(true)
.NET ForcePathStyle = true
Ruby force_path_style: true

When running inside Simfra containers, path-style is configured automatically via AWS_S3_US_EAST_1_REGIONAL_ENDPOINT=regional.

TLS / HTTPS

Simfra serves HTTP (not HTTPS) by default. SDK clients connecting from the host use http://localhost:4599. No TLS certificates are needed.

Inside Docker containers, connections to Simfra also use HTTP. The AWS_ENDPOINT_URL injected by Simfra always uses the http:// scheme.

Next Steps