Portfolio · Notes · Dotfiles

Search everything

Search case studies, engineering notes, and Dotfiles documentation.

    all case studies

    Case study 16

    Self-service cloud functions for customer code

    Customer extensions move from upload to a running Lambda through automated builds and a small provisioning API, with function-specific roles, authenticated invocation, and logs.

    My role
    Implemented the selected AWS architecture, introduced Crossplane, and built the infrastructure, build workflow, and provisioning controls.
    Evidence
    The SDK service provisions functions through a Kubernetes claim; the composition supplies a per-function IAM role, IAM-authenticated function URL, and log group.
    securitydelivery

    Deliver the selected runtime architecture

    The product needed to run customer-written server-side extensions. An earlier evaluation compared hosted runtimes with an AWS implementation and selected Lambda based on isolation, maturity, data residency, and control over the platform.

    I took that decision into implementation. I introduced Crossplane and built the Terraform infrastructure, build workflow, and provisioning integration. The goal was to let the product create functions without a platform engineer configuring cloud resources for each upload.

    Separate building code from provisioning resources

    The build workflow starts when an extension is uploaded to S3 as <name>/<version>/lambda.zip. EventBridge starts a Step Functions execution, which records the version’s build state in DynamoDB, runs CodeBuild, publishes a container image, and records the resulting image URI.

    The provisioning workflow starts after a successful build. The SDK service creates a LambdaFunction claim in Kubernetes, and a Crossplane composition creates the corresponding AWS resources.

    EXHIBIT — FROM UPLOAD TO RUNNING FUNCTION
    BUILD PLANE · TERRAFORM + STEP FUNCTIONSPROVISIONING PLANE · CROSSPLANEApp developeruploads extensionApp SDK serviceS3lambda.zipStep Functionsevent rulePer-version lockDynamoDB · TTL reclaimCodeBuildimage from shared DockerfileRegistryRecord version + latest pointerApp SDK servicepolls build statusLambdaFunction objectKubernetesCrossplane compositionLambdaIAM role · IAM-authenticated URL · logs

    That separation keeps image construction and cloud-resource reconciliation independently observable. The SDK consumes the completed build record rather than reconstructing the build process.

    Keep the provisioning interface small

    The SDK supplies the image and runtime settings through one object. This shortened example uses a fictional API group, image repository, and account:

    functions/example-extension.yaml
    apiVersion: example.com/v1alpha1
    kind: LambdaFunction
    metadata:
    name: example-extension
    spec:
    imageUri: >-
    111111111111.dkr.ecr.eu-west-1.amazonaws.com/functions:v1
    memorySize: 256
    timeout: 20
    permissionsBoundaryArn: >-
    arn:aws:iam::111111111111:policy/function-boundary
    resourceConfig:
    region: eu-west-1
    compositionSelector:
    matchLabels:
    type: container

    The composition creates a function-specific IAM role and applies the supplied permissions boundary. Invocation uses an IAM-authenticated function URL with response streaming enabled. Each function also gets a log group so developers can inspect their extension’s output.

    The SDK service has a dedicated Kubernetes role for managing function claims. Customer code executes in the resulting Lambda; it does not receive the SDK’s provisioning role. Platform ownership labels keep the dynamically created resources visible in shared monitoring.

    Handle retries and lifecycle edges explicitly

    The build workflow checks for an active build or an existing successful version before starting work. It uses a version-scoped lock, handles lock contention, and includes recovery for expired locks. Successful versions have a separate artifact record, allowing repeated events to be recognized.

    Cleanup also needed attention when a function object was removed partway through provisioning. The composition declares deletion behavior for its managed resources, and the integration includes cleanup for stale composite objects.

    The selected runtime carries constraints: a 15-minute execution limit and cold-start latency. Those belong in the architecture decision because they affect which customer extensions the platform can support.

    What changed

    The product gained an automated path from extension upload to a running function with its own identity, invocation controls, and logs. The platform team owns the shared build and provisioning machinery; individual functions use the same interface without a manual infrastructure request.