Skip to content

jvdborre/TRPS-INTERNAL-SNOWFLAKE-SCIMKEY

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

TRPS Internal - Snowflake SCIM Key Rotator (AWS CDK, Python)

This repository contains an AWS CDK v2 application (written in Python) that runs a monthly rotation job for multiple Snowflake tenants:

  1. Connects to each configured Snowflake tenant
  2. Executes a SQL query that returns a new SCIM key for that tenant
  3. Stores the key in AWS Systems Manager Parameter Store (SSM) per tenant
  4. Calls OneLogin to update the SCIM key/token for the tenant's Snowflake application

Multi-Tenant Architecture

The application supports rotating SCIM keys for multiple Snowflake tenants in a single Lambda invocation:

  • Single OneLogin tenant: One shared OneLogin instance with API key authentication
  • Multiple Snowflake applications: Each tenant represents a different Snowflake application in OneLogin
  • Tenant-based Snowflake config: Each tenant has its own Snowflake connection (key-pair authentication)
  • Tenant list: A master SSM parameter lists all tenant IDs to process
  • Isolated processing: Each tenant is processed independently; failures in one tenant don't affect others
  • Single or batch mode: Can process all tenants (default) or a specific tenant via event payload

Authentication Methods

  • OneLogin: API key authentication (shared across all tenants)
    • Format: Authorization: Bearer api_key:<api_key>
  • Snowflake: Key-pair authentication only (per tenant)
    • Uses RSA private key (PEM format)
    • Optional passphrase support

What gets deployed

  • Lambda: runs the rotation logic for all configured tenants
  • EventBridge Schedule: triggers Lambda monthly (processes all tenants)
  • CloudWatch Logs: Lambda logs with tenant-specific prefixes
  • IAM: least-privilege access to tenant-specific SSM parameters

Prerequisites

  • AWS credentials configured for the target account
  • AWS CDK installed (CDK CLI)
  • Python 3.11+
  • Docker (for Lambda dependency bundling)

SSM Parameter Structure

Shared OneLogin Configuration (Required - Single Instance)

  • /trps/scimkey/onelogin/base_url (String) - OneLogin API base URL (e.g., https://api.us.onelogin.com)
  • /trps/scimkey/onelogin/api_key (SecureString) - OneLogin API key for authentication

Tenant List (Required)

  • /trps/scimkey/tenants/list (String)
    • Comma-separated list: tenant1,tenant2,tenant3
    • Or JSON array: ["tenant1","tenant2","tenant3"]

Per-Tenant Configuration

For each tenant ID (e.g., tenant1), create the following parameters:

Snowflake Configuration (/trps/scimkey/tenants/{tenant_id}/snowflake/*)

  • account (String) - Snowflake account identifier
  • user (String) - Snowflake username
  • private_key (SecureString) - RSA private key in PEM format (including BEGIN/END markers)
  • private_key_passphrase (SecureString, optional) - Passphrase for the private key (if encrypted)
  • warehouse (String) - Snowflake warehouse name
  • role (String) - Snowflake role name
  • database (String) - Snowflake database name
  • schema (String) - Snowflake schema name
  • scim_key_sql (String) - SQL query that returns one row, one column with the SCIM key

OneLogin Application Configuration (/trps/scimkey/tenants/{tenant_id}/onelogin/*)

  • ppid (String) - OneLogin application ppId for this Snowflake application (e.g., ABC234)
  • update_endpoint (String) - API endpoint path (e.g., /api/2/apps/{ppid})
  • scim_key_field (String) - JSON field name for SCIM key (e.g., scim_token)

Output Parameter (/trps/scimkey/tenants/{tenant_id}/current_scim_key)

  • current_scim_key (SecureString) - Stores the current SCIM key (overwritten each rotation)

Setup

1. Install Dependencies

python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

2. Configure OneLogin (Shared Configuration)

# Set up shared OneLogin API credentials (one-time setup)
./scripts/setup_onelogin.sh

3. Configure Tenants

Option A: Use Helper Scripts (Recommended)

# Set up tenant list
./scripts/setup_tenant_list.sh tenant1,tenant2,tenant3

# Configure each tenant (Snowflake + OneLogin app settings)
./scripts/setup_tenant.sh tenant1
./scripts/setup_tenant.sh tenant2
./scripts/setup_tenant.sh tenant3

Option B: Manual Setup

# Create tenant list
aws ssm put-parameter \
    --name "/trps/scimkey/tenants/list" \
    --value "tenant1,tenant2" \
    --type "String" \
    --overwrite

# Create tenant-specific parameters (example for tenant1)
aws ssm put-parameter --name "/trps/scimkey/tenants/tenant1/snowflake/account" --value "your-account" --type "String"
aws ssm put-parameter --name "/trps/scimkey/tenants/tenant1/snowflake/user" --value "your-user" --type "String"
aws ssm put-parameter --name "/trps/scimkey/tenants/tenant1/snowflake/password" --value "your-password" --type "SecureString"
# ... (continue for all parameters)

4. Bootstrap CDK (if needed)

cdk bootstrap

5. Deploy

cdk deploy

Usage

Automatic Rotation (Monthly)

The EventBridge schedule automatically triggers the Lambda on the 1st day of each month at 2:00 AM UTC, processing all tenants listed in /trps/scimkey/tenants/list.

Manual Testing

Test All Tenants

FUNCTION_NAME="ScimKeyRotatorStack-RotateScimKeyFunction-XXXXX"

aws lambda invoke \
    --function-name "$FUNCTION_NAME" \
    --payload '{}' \
    response.json

cat response.json | python3 -m json.tool

Test Single Tenant

aws lambda invoke \
    --function-name "$FUNCTION_NAME" \
    --payload '{"tenant_id": "tenant1"}' \
    response.json

cat response.json | python3 -m json.tool

Or use the helper script:

./scripts/test_lambda.sh "$FUNCTION_NAME"

Response Format

{
  "statusCode": 200,
  "body": {
    "message": "Processed 3 tenant(s): 3 successful, 0 failed",
    "results": [
      {
        "tenant_id": "tenant1",
        "status": "success",
        "ppid": "ABC234"
      },
      {
        "tenant_id": "tenant2",
        "status": "success",
        "ppid": "XYZ789"
      },
      {
        "tenant_id": "tenant3",
        "status": "failed",
        "error": "Connection timeout"
      }
    ],
    "summary": {
      "total": 3,
      "successful": 2,
      "failed": 1
    }
  }
}

Adding/Removing Tenants

Add a New Tenant

  1. Configure the tenant:

    ./scripts/setup_tenant.sh new-tenant-id
  2. Add to tenant list:

    # Get current list
    CURRENT_LIST=$(aws ssm get-parameter --name /trps/scimkey/tenants/list --query 'Parameter.Value' --output text)
    
    # Append new tenant
    aws ssm put-parameter \
        --name "/trps/scimkey/tenants/list" \
        --value "${CURRENT_LIST},new-tenant-id" \
        --type "String" \
        --overwrite

    Or use the helper script:

    ./scripts/setup_tenant_list.sh tenant1,tenant2,new-tenant-id

Remove a Tenant

  1. Remove from tenant list:

    ./scripts/setup_tenant_list.sh tenant1,tenant2  # Remove tenant3
  2. (Optional) Delete tenant parameters:

    # List all parameters for the tenant
    aws ssm get-parameters-by-path --path "/trps/scimkey/tenants/tenant3" --recursive
    
    # Delete them (be careful!)
    aws ssm delete-parameter --name "/trps/scimkey/tenants/tenant3/..."

Monitoring

  • CloudWatch Logs: /aws/lambda/ScimKeyRotatorStack-RotateScimKeyFunction-*
    • Logs include tenant ID prefix: [tenant1], [tenant2], etc.
  • EventBridge Schedule: Runs on the 1st day of each month at 2:00 AM UTC
  • Lambda Metrics: Check CloudWatch metrics for success/failure rates per invocation
  • Response Status Codes:
    • 200: All tenants processed successfully
    • 207: Partial success (some tenants failed)
    • 500: Failed to process tenant list or critical error

Lambda Dependencies

The Lambda uses:

  • boto3 (AWS SDK - included in runtime)
  • snowflake-connector-python
  • requests
  • cryptography (for parsing RSA private keys)

CDK bundles dependencies using Docker during deployment.

Architecture Notes

  • Single OneLogin Tenant: One shared OneLogin instance with API key authentication
  • Multiple Snowflake Applications: Each tenant represents a different Snowflake application in OneLogin
  • Tenant Isolation: Each tenant's Snowflake configuration and SCIM key are stored separately
  • Error Handling: Failures in one tenant don't stop processing of other tenants
  • Scalability: Can handle any number of tenants (limited by Lambda timeout/memory)
  • Flexibility: Each tenant can have different:
    • Snowflake accounts
    • Snowflake users/keys
    • SQL queries for SCIM key retrieval
    • OneLogin application ppIds (different apps in the same OneLogin tenant)

Troubleshooting

Tenant Not Processing

  1. Check tenant is in the list:

    aws ssm get-parameter --name /trps/scimkey/tenants/list
  2. Verify tenant parameters exist:

    aws ssm get-parameters-by-path --path "/trps/scimkey/tenants/tenant1" --recursive
  3. Check CloudWatch Logs for tenant-specific errors

Lambda Timeout

If processing many tenants, consider:

  • Increasing Lambda timeout in infra/scimkey_rotator_stack.py
  • Using Step Functions for parallel processing (future enhancement)
  • Processing tenants in batches

Future Enhancements

  • Step Functions orchestration for parallel tenant processing
  • CloudWatch alarms for failed tenant rotations
  • SNS notifications on failures
  • Dry-run mode for testing without updating OneLogin
  • Support for multiple OneLogin tenants (if needed)

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors