Linking in Stelvio is a powerful concept that automates IAM permission management and environment variable configuration between AWS resources.
What is a Link?
A Link represents a connection between two resources in your infrastructure. It defines:
Permissions: The IAM policies that allow one resource to interact with another (such as a Lambda function accessing a DynamoDB table)
Properties: Key-value pairs that one resource shares with another (like environment variables passed to a Lambda function)
Links make it easy to establish secure, properly configured connections between resources without manually setting up complex IAM policies or environment configurations.
How Linking Works
Resources that can be linked implement the Linkable protocol, which requires a link() method that returns a Link object. This object contains default permissions and properties appropriate for that resource type.
Default Link Permissions
When Stelvio creates links automatically, each resource type provides sensible default permissions:
DynamoDB Table → Lambda/API
When you link a DynamoDB table to a Lambda function or API route, you get these permissions by default:
dynamodb:Scan - Full table scan operations
dynamodb:Query - Query using partition key (and sort key)
dynamodb:GetItem - Retrieve single items by primary key
dynamodb:PutItem - Create or replace items
dynamodb:UpdateItem - Modify existing items
dynamodb:DeleteItem - Delete items by primary key
Plus these environment variables:
- STLV_{TABLE_NAME}_TABLE_ARN - The table's ARN
- STLV_{TABLE_NAME}_TABLE_NAME - The table's name
This gives your Lambda full read/write access to the table.
When you link a Function to another Lambda function, you get this permission by default:
lambda:InvokeFunction - Invoke the target function
Plus these environment variables:
STLV_{FUNCTION_NAME}_FUNCTION_ARN - The function's ARN
STLV_{FUNCTION_NAME}_FUNCTION_NAME - The function's name
This allows your Lambda to invoke the linked function using boto3.
Generated Resource Access
When you link resources to Lambda functions, Stelvio automatically generates a stlv_resources.py file in your Lambda's source directory. This file provides type-safe, IDE-friendly access to all linked resources:
fromstlv_resourcesimportResourcesimportboto3dynamodb=boto3.resource('dynamodb')table=dynamodb.Table(Resources.todos.table_name)defhandler(event,context):# Your IDE knows about Resources.todos and provides autocomplete!print(f"Table ARN: {Resources.todos.table_arn}")# Use the tabletable.put_item(Item={'id':'123','data':'example'})
Generation Timing
The stlv_resources.py file is generated or updated in your function's source directory whenever you run stlv diff or stlv deploy. This file is automatically packaged and deployed with your Lambda function.
Using Links
Basic Linking
fromstelvio.aws.dynamo_dbimportAttributeType,DynamoTablefromstelvio.aws.functionimportFunction# Create a DynamoDB tabletable=DynamoTable(name="todos",fields={"username":AttributeType.STRING},partition_key="username")# Link the table to a Lambda functionfn=Function(handler="users/handler.process",links=[table]# Link the table to the function)
When you link a DynamoDB table to a Lambda function, Stelvio automatically:
Creates IAM permissions allowing the Lambda to perform operations on the table
Passes the table ARN and name as environment variables to the Lambda
You can also create standalone links with custom properties and permissions:
fromstelvio.linkimportLinkfromstelvio.aws.permissionimportAwsPermission# Create a custom link with specific propertiescustom_link=Link(name="custom-config",properties={"api_url":"https://example.com/api","timeout":"30"},permissions=None)# Link with specific permissions to an S3 buckets3_link=Link(name="logs-bucket",properties={"bucket_name":"my-logs-bucket"},permissions=[AwsPermission(actions=["s3:GetObject","s3:PutObject"],resources=["arn:aws:s3:::my-logs-bucket/*"])])# Use these custom links with a functionfn=Function(handler="functions/process.handler",links=[custom_link,s3_link])
Customizing Links
You can customize links using various methods which all return a new Link instance (the original link remains unchanged):
with_properties() - Replace all properties
with_permissions() - Replace all permissions
add_properties() - Add to existing properties
add_permissions() - Add to existing permissions
remove_properties() - Remove specific properties
Example:
# Create a read-only link to the table (creates a new Link object)read_only_link=table.link().with_permissions(AwsPermission(actions=["dynamodb:GetItem","dynamodb:Query","dynamodb:Scan"],resources=[table.arn]))# Link with custom properties (creates a new Link object)fn=Function(handler="users/handler.process",links=[table.link().add_properties(table_region="us-west-2")])
Overriding Default Link Creation
You can override how links are created for specific component types by providing custom link configurations to your Stelvio application:
fromstelvio.appimportStelvioAppfrompulumi_aws.dynamodbimportTablefromstelvio.aws.dynamo_dbimportDynamoTablefromstelvio.linkimportLinkConfigfromstelvio.aws.permissionimportAwsPermission# Define a custom link creation functiondefread_only_dynamo_link(table:Table)->LinkConfig:returnLinkConfig(properties={"table_arn":table.arn,"table_name":table.name},permissions=[AwsPermission(actions=["dynamodb:GetItem","dynamodb:Query","dynamodb:Scan"],resources=[table.arn])])# Initialize app with custom link configsapp=StelvioApp(name="my-app",link_configs={DynamoTable:read_only_dynamo_link# Override default DynamoTable link creation})
Next Steps
Now that you understand linking, you might want to explore: