CI/CD Pipelines¶
Query the LightPane API from your CI/CD pipeline to check infrastructure state before, during, or after a deployment. Use cases include:
- Verify expected resources exist before deploying
- Check that no CloudWatch alarms are firing before a release
- Log the current infrastructure state as a deployment artifact
- Block a deploy if infrastructure does not match expectations
Requirements:
- A LightPane API key (
csl_ak_prefix) — create one here - The API key stored as a CI secret (not in code)
Store the token as a secret¶
Add the token as a repository secret named LIGHTPANE_API_KEY:
- Go to Settings > Secrets and variables > Actions
- Click New repository secret
- Name:
LIGHTPANE_API_KEY - Value: your
csl_ak_token
Add the token as a CI/CD variable:
- Go to Settings > CI/CD > Variables
- Click Add variable
- Key:
LIGHTPANE_API_KEY - Value: your
csl_ak_token - Check Mask variable
Add the token as a credential:
- Go to Manage Jenkins > Credentials
- Add a Secret text credential
- ID:
lightpane-api-key - Secret: your
csl_ak_token
Check infrastructure before deploying¶
GitHub Actions¶
.github/workflows/deploy.yml
name: Deploy
on:
push:
branches: [main]
jobs:
check-infra:
runs-on: ubuntu-latest
steps:
- name: Check infrastructure state
env:
LIGHTPANE_API_KEY: ${{ secrets.LIGHTPANE_API_KEY }}
run: |
RESPONSE=$(curl -s -w "\n%{http_code}" \
-X POST https://api.lightpane.cloud/services/discover \
-H "Authorization: Bearer $LIGHTPANE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"services": [
{"service": "ec2", "provider": "aws", "region": "eu-west-2",
"attributes": ["name", "instance_id", "state"]}
]
}')
HTTP_CODE=$(echo "$RESPONSE" | tail -1)
BODY=$(echo "$RESPONSE" | head -n -1)
if [ "$HTTP_CODE" != "200" ]; then
echo "LightPane API returned $HTTP_CODE"
echo "$BODY"
exit 1
fi
echo "$BODY" | jq .
deploy:
needs: check-infra
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Deploy application
run: echo "Deploying..."
GitLab CI¶
.gitlab-ci.yml
check-infra:
stage: pre-deploy
image: curlimages/curl:latest
script:
- |
RESPONSE=$(curl -s -w "\n%{http_code}" \
-X POST https://api.lightpane.cloud/services/discover \
-H "Authorization: Bearer $LIGHTPANE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"services": [
{"service": "ec2", "provider": "aws", "region": "eu-west-2",
"attributes": ["name", "instance_id", "state"]}
]
}')
HTTP_CODE=$(echo "$RESPONSE" | tail -1)
if [ "$HTTP_CODE" != "200" ]; then
echo "Infrastructure check failed"
exit 1
fi
Check for active CloudWatch alarms¶
Block a deploy if any CloudWatch alarms are in ALARM state:
check_alarms.sh
#!/bin/bash
set -e
RESPONSE=$(curl -s \
-X POST https://api.lightpane.cloud/services/discover \
-H "Authorization: Bearer $LIGHTPANE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"services": [
{"service": "cloudwatch_alarms", "provider": "aws", "region": "eu-west-2",
"attributes": ["alarm_name", "state_value", "metric_name"]}
]
}')
ALARM_COUNT=$(echo "$RESPONSE" | jq '[.results[0].rows[] | select(.state_value == "ALARM")] | length')
if [ "$ALARM_COUNT" -gt "0" ]; then
echo "BLOCKED: $ALARM_COUNT CloudWatch alarms are firing"
echo "$RESPONSE" | jq '.results[0].rows[] | select(.state_value == "ALARM")'
exit 1
fi
echo "No active alarms. Proceeding with deploy."
Save infrastructure state as a build artifact¶
Capture the current state of your infrastructure and store it alongside the deployment for audit purposes.
.github/workflows/deploy.yml
- name: Capture infrastructure state
env:
LIGHTPANE_API_KEY: ${{ secrets.LIGHTPANE_API_KEY }}
run: |
curl -s \
-X POST https://api.lightpane.cloud/services/discover \
-H "Authorization: Bearer $LIGHTPANE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"services": [
{"service": "ec2", "provider": "aws", "region": "eu-west-2"},
{"service": "rds_instances", "provider": "aws", "region": "eu-west-2"},
{"service": "lambda_functions", "provider": "aws", "region": "eu-west-2"}
]
}' > infra-state.json
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: infra-state-${{ github.sha }}
path: infra-state.json
Python pre-deploy check¶
For more complex validation, use a Python script:
pre_deploy_check.py
import os
import sys
import requests
API_URL = "https://api.lightpane.cloud/services/discover"
TOKEN = os.environ["LIGHTPANE_API_KEY"]
# Define expected infrastructure
EXPECTED = {
"ec2": {"min_running": 2},
"rds_instances": {"min_count": 1},
}
response = requests.post(API_URL, json={
"services": [
{"service": "ec2", "provider": "aws", "region": "eu-west-2",
"attributes": ["name", "instance_id", "state"]},
{"service": "rds_instances", "provider": "aws", "region": "eu-west-2",
"attributes": ["name", "engine", "status"]},
]
}, headers={
"Authorization": f"Bearer {TOKEN}",
"Content-Type": "application/json"
})
response.raise_for_status()
data = response.json()
failed = False
for result in data.get("results", []):
service = result["metadata"]["service"]
rows = result.get("rows", [])
if service == "ec2":
running = [r for r in rows if r.get("state") == "running"]
if len(running) < EXPECTED["ec2"]["min_running"]:
print(f"FAIL: Expected at least {EXPECTED['ec2']['min_running']} "
f"running EC2 instances, found {len(running)}")
failed = True
if service == "rds_instances":
if len(rows) < EXPECTED["rds_instances"]["min_count"]:
print(f"FAIL: Expected at least {EXPECTED['rds_instances']['min_count']} "
f"RDS instance(s), found {len(rows)}")
failed = True
if failed:
sys.exit(1)
print("All pre-deploy checks passed.")
Access key recommendations for CI/CD¶
| Setting | Recommendation |
|---|---|
| Type | api_key |
allowed_ips |
Set to your CI runner IP range if known |
rate_limit_rpm |
60 is sufficient for most pipelines |
| Services | Scope to only the services your pipeline checks |
| Expiry | Set to match your key rotation schedule (90 days or 1 year) |
Do not commit tokens to version control
Store the token as a CI secret. If a token is accidentally committed, revoke it immediately in Access Keys and create a new one.