Multi-Source Example
Production configuration collecting evidence from GitHub, AWS, and Google Workspace.
Use Case
Perfect for:
- Production environments
- Complete SOC 2 Type I compliance
- Multiple evidence sources
- Full control coverage (CC6.1, CC6.6, CC7.2)
Coverage: All 3 controls across 3 sources
What This Collects
| Control | Source | Evidence |
|---|---|---|
| CC6.1 | GitHub | Organization 2FA enforcement |
| CC6.1 | AWS | IAM password policy |
| CC6.1 | Google Workspace | 2-Step Verification enforcement |
| CC6.6 | GitHub | CODEOWNERS files |
| CC6.6 | Google Workspace | Admin role assignments |
| CC7.2 | GitHub | Branch protection rules |
| CC7.2 | AWS | CloudTrail logging status |
Total artifacts: ~9-12 files
Prerequisites
1. GitHub
- Personal access token with
repo:read,read:orgscopes - Organization with 2FA enforced
- Repositories with branch protection
2. AWS
- IAM user with read-only permissions
- Access key ID and secret access key
- CloudTrail configured and logging
3. Google Workspace
- Service account with domain-wide delegation
- Required OAuth scopes authorized
- 2-Step Verification enforced
Complete Configuration
evidence.yaml
# evidence.yaml - Production multi-source configuration
framework: soc2_type1
controls:
- CC6.1 # Logical Access Controls
- CC6.6 # Access Removal/Modification
- CC7.2 # Change Management
sources:
# GitHub: Code repository evidence
github:
mode: token
token_env: GITHUB_TOKEN
org: acme
repos: '*' # All repositories
branch: main
# AWS: Infrastructure evidence
aws:
mode: env
region: us-east-1
log_groups:
- /aws/lambda/production-*
cloudtrail:
trails:
- production-audit-trail
# Google Workspace: Identity management evidence
google_workspace:
mode: service_account
credentials_env: GOOGLE_APPLICATION_CREDENTIALS
customer_id: C01234567
admin_email: evidence-admin@acme.com
domains:
- acme.com
bundle:
signing:
private_key_path: /etc/evidence/keys/production.pem
key_id: production-2026-01
output_path: /var/evidence/bundles
max_size_mb: 100
naming_pattern: '{org}-{framework}-{timestamp}'
upload:
enabled: true
retention_days: 730 # 2 years
tags:
environment: production
team: security
compliance: soc2
verify_before_upload: trueEnvironment Variables
Production Server
Create /etc/evidence/.env:
# GitHub
GITHUB_TOKEN=ghp_production_token_here
# AWS
AWS_ACCESS_KEY_ID=AKIA_production_key
AWS_SECRET_ACCESS_KEY=production_secret_key
AWS_REGION=us-east-1
# Google Workspace
GOOGLE_APPLICATION_CREDENTIALS=/etc/evidence/keys/google-service-account.json
# Evidence Platform
EVIDENCE_API_KEY=evd_api_production_key_hereLoad before collection:
source /etc/evidence/.env
evidence collectGitHub Actions (Alternative)
Use secrets for automated collection:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
GOOGLE_APPLICATION_CREDENTIALS: /tmp/google-sa.json
EVIDENCE_API_KEY: ${{ secrets.EVIDENCE_API_KEY }}Setup Instructions
1. GitHub Setup
Create token:
- GitHub → Settings → Developer settings → Personal access tokens
- Generate new token (classic)
- Name:
evidence-production - Scopes:
repo,read:org - Expiration: 90 days
- Generate and copy token
Set environment variable:
export GITHUB_TOKEN=ghp_production_token_here2. AWS Setup
Create IAM user:
aws iam create-user --user-name evidence-collector-production
# Attach policy
aws iam put-user-policy \
--user-name evidence-collector-production \
--policy-name EvidenceCollection \
--policy-document file://evidence-policy.jsonPolicy (evidence-policy.json):
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"iam:GetAccountPasswordPolicy",
"cloudtrail:DescribeTrails",
"cloudtrail:GetTrailStatus",
"logs:DescribeLogGroups"
],
"Resource": "*"
}
]
}Create access key:
aws iam create-access-key --user-name evidence-collector-productionSet environment variables:
export AWS_ACCESS_KEY_ID=AKIA_key_from_above
export AWS_SECRET_ACCESS_KEY=secret_from_above3. Google Workspace Setup
Create service account:
- Go to Google Cloud Console
- IAM & Admin → Service Accounts
- Create service account:
evidence-collector-production - Create JSON key
- Download to
/etc/evidence/keys/google-service-account.json
Enable domain-wide delegation:
- Copy client ID from service account
- Go to Admin Console
- Security → API controls → Domain-wide Delegation
- Add client ID with scopes:
https://www.googleapis.com/auth/admin.directory.user.readonly https://www.googleapis.com/auth/admin.directory.rolemanagement.readonly https://www.googleapis.com/auth/admin.reports.audit.readonly
Set environment variable:
export GOOGLE_APPLICATION_CREDENTIALS=/etc/evidence/keys/google-service-account.json4. Generate Signing Keys
evidence init --generate-keys --key-id production-2026-01Move to production location:
sudo mkdir -p /etc/evidence/keys
sudo mv ~/.evidence/keys/private.pem /etc/evidence/keys/production.pem
sudo chmod 600 /etc/evidence/keys/production.pem5. Get evidence Platform API Key
- Log in to evidence platform
- Settings → API Keys
- Create API Key
- Permissions:
bundles:create,bundles:upload - Copy key (starts with
evd_api_)
Set environment variable:
export EVIDENCE_API_KEY=evd_api_your_key_hereCollection
Run Collection
evidence collectExpected output:
Validating configuration...
✓ Configuration valid (3 sources)
✓ Signing key found
✓ All environment variables set
Validating credentials...
✓ GitHub token valid (scopes: repo, read:org)
✓ AWS credentials valid (account: 123456789012)
✓ Google Workspace service account valid
Collecting from GitHub...
→ Fetching organization settings
→ Discovering repositories (47 found)
→ Fetching branch protection (47 repos)
→ Fetching CODEOWNERS (44 repos)
✓ GitHub: 93 artifacts collected
Collecting from AWS...
→ Fetching IAM password policy
→ Fetching CloudTrail status (production-audit-trail)
→ Fetching CloudWatch log groups (12 found)
✓ AWS: 14 artifacts collected
Collecting from Google Workspace...
→ Fetching 2SV enforcement
→ Fetching admin roles (5 roles)
→ Fetching user lifecycle events
✓ Google Workspace: 3 artifacts collected
Creating bundle...
→ Generating manifest
→ Computing checksums (110 files)
→ Signing bundle
✓ Bundle created: acme-soc2_type1-20260110-143022.tar.gz
Verifying bundle...
✓ Checksums valid (110/110 files)
✓ Signature valid
Uploading to evidence platform...
✓ Authenticated (organization: acme)
✓ Upload complete (35.7 KB in 2.1s)
✓ Verified on platform
✓ Collection complete
Bundle ID: bundle_abc123def456
Platform URL: https://app.evidence-platform.com/bundles/bundle_abc123def456
Summary:
Framework: soc2_type1
Controls: CC6.1, CC6.6, CC7.2
Sources: github, aws, google_workspace
Artifacts: 110
Size: 35.7 KB (compressed)
Duration: 23.4 secondsVerification
Verify Bundle Locally
evidence verify /var/evidence/bundles/acme-soc2_type1-*.tar.gzOutput:
Verifying bundle...
✓ Checksums valid (110/110 files)
✓ Signature valid
Bundle is authentic and unmodified.
Control Coverage:
CC6.1: Complete (3/3 sources)
CC6.6: Complete (2/2 sources)
CC7.2: Complete (2/2 sources)
Bundle Details:
Framework: soc2_type1
Controls: CC6.1, CC6.6, CC7.2
Sources: github, aws, google_workspace
Artifacts: 110
Created: 2026-01-10T14:30:22Z
Signed: production-2026-01Inspect Bundle Contents
tar -xzf /var/evidence/bundles/acme-soc2_type1-*.tar.gz -C /tmp/inspect
tree /tmp/inspectStructure:
/tmp/inspect/
├── manifest.json
├── run.json
├── checksums.sha256
├── signature.sig
├── sources/
│ ├── github/
│ │ ├── org_settings.json
│ │ ├── repo_acme_backend_branch_protection.json
│ │ ├── repo_acme_backend_codeowners.json
│ │ ├── repo_acme_frontend_branch_protection.json
│ │ ... (93 total)
│ ├── aws/
│ │ ├── iam_password_policy.json
│ │ ├── cloudtrail_trail_production_status.json
│ │ ├── cloudwatch_log_group_aws_lambda_production_api.json
│ │ ... (14 total)
│ └── google_workspace/
│ ├── 2sv_enforcement.json
│ ├── admin_roles.json
│ └── user_lifecycle.json
└── derived/
├── normalized.json
└── hints.jsonAutomation
Cron Job
# /etc/cron.d/evidence-collection
# Collect evidence on first day of each month at 2 AM
0 2 1 * * evidence source /etc/evidence/.env && evidence collect >> /var/log/evidence-collection.log 2>&1systemd Timer
Service file (/etc/systemd/system/evidence-collection.service):
[Unit]
Description=Evidence Collection
After=network.target
[Service]
Type=oneshot
User=evidence
EnvironmentFile=/etc/evidence/.env
ExecStart=/usr/bin/evidence collect
WorkingDirectory=/var/evidenceTimer file (/etc/systemd/system/evidence-collection.timer):
[Unit]
Description=Monthly Evidence Collection
Requires=evidence-collection.service
[Timer]
OnCalendar=monthly
Persistent=true
[Install]
WantedBy=timers.targetEnable:
sudo systemctl enable evidence-collection.timer
sudo systemctl start evidence-collection.timerProduction Considerations
Security
-
Credentials storage:
- Use secrets manager (Vault, AWS Secrets Manager)
- Restrict file permissions (600)
- Rotate credentials quarterly
-
Access control:
- Dedicated service account
- Least privilege permissions
- Audit access logs
-
Key management:
- Separate keys per environment
- Annual rotation schedule
- Encrypted backups
Monitoring
Check collection success:
# View recent bundles
ls -lt /var/evidence/bundles/ | head -5
# Check last collection log
tail -50 /var/log/evidence-collection.log
# Verify upload
curl -H "Authorization: Bearer $EVIDENCE_API_KEY" \
https://api.evidence-platform.com/bundles/latestAlerts:
- Email notification on failure
- Platform notification on upload
- Slack integration for team visibility
Retention
Local bundles:
# Keep last 6 months locally
find /var/evidence/bundles -name "*.tar.gz" -mtime +180 -deletePlatform bundles:
- Configured in
upload.retention_days: 730 - Auto-deleted after 2 years
- Export before deletion if needed
Troubleshooting
Rate Limiting (GitHub)
Error:
✗ GitHub connector failed
Error: API rate limit exceededSolution:
- Collection pauses automatically
- Wait for reset (up to 1 hour)
- Or schedule collection during off-hours
Bundle Too Large
Error:
✗ Bundle creation failed
Error: Bundle size (125 MB) exceeds maximum (100 MB)Solution:
- Increase limit:
max_size_mb: 200 - Reduce scope: Limit repos or log groups
- Disable verbose manifest
Upload Timeout
Error:
✗ Upload failed
Error: Request timeout after 300sSolution:
- Increase timeout:
upload.timeout_seconds: 600 - Check network connectivity
- Reduce bundle size
See Also
- Minimal GitHub Example - Simpler starting point
- GitHub Action Workflow - CI/CD automation
- Configuration Guide - Advanced options
- Credential Management - Security best practices
- Troubleshooting - Common issues