SEAGIT DOCS
Variables & Secrets

Variables & Secrets

Manage configuration and sensitive data across your organization with a powerful five-level hierarchy and inheritance system.

Hierarchy & Inheritance

SeaGit uses a five-level hierarchy for variables and secrets, allowing you to define configuration once and inherit it across your entire infrastructure.

Level 1: Organization

Global configuration shared across all environments, clusters, applications, and instances.

Example: AWS_REGION, LOG_LEVEL, COMPANY_NAME

Level 2: Environment

Shared across all clusters and applications in this environment (dev, staging, prod).

Example: DATABASE_HOST, API_ENDPOINT, DOMAIN_NAME

Level 3: Cluster

Specific to a Kubernetes cluster within an environment.

Example: CLUSTER_REGION, NODE_TYPE, K8S_VERSION

Level 4: Application

Shared across all instances of an application template.

Example: APP_NAME, DEFAULT_TIMEOUT, CACHE_TTL

Level 5: Instance

Specific to a single application instance. Highest priority - overrides all other levels.

Example: REPLICAS, MEMORY_LIMIT, FEATURE_FLAGS

Inheritance Rules:

  • • Variables cascade down from Organization → Environment → Cluster → Application → Instance
  • • Child levels inherit parent values automatically
  • • Child levels can override parent values by defining same variable name
  • • Instance level has highest priority (final override)
  • • Secrets follow same inheritance rules as variables

Example Inheritance:

Organization: LOG_LEVEL=info, MAX_CONNECTIONS=100
Environment:  LOG_LEVEL=debug (overrides org)
Cluster:      DATABASE_HOST=db.cluster1.local
Application:  APP_NAME=api-service
Instance:     LOG_LEVEL=error (overrides both org and env)

Final values in instance:
  LOG_LEVEL=error           # From instance (highest priority)
  MAX_CONNECTIONS=100       # From organization (inherited)
  DATABASE_HOST=db.cluster1 # From cluster (inherited)
  APP_NAME=api-service      # From application (inherited)

Variables vs Secrets

Variables

  • Visibility: Visible in UI and API responses
  • Use Cases: Non-sensitive configuration
    • - Feature flags
    • - API endpoints
    • - Port numbers
    • - Environment names
    • - Log levels
  • Storage: Plain text in database
  • Access: Viewable by all users with access

Secrets

  • Visibility: Hidden (shown as ****)
  • Use Cases: Sensitive data
    • - Database passwords
    • - API keys
    • - TLS certificates
    • - Encryption keys
    • - OAuth tokens
  • Storage: Encrypted at rest
  • Access: Write-only via UI (cannot view after creation)

Important:

Both variables and secrets are injected as environment variables into your containers. The distinction is only in how they're stored and displayed in SeaGit. Applications access them identically using process.env.VARIABLE_NAME.

Managing Variables

Adding Variables

  1. 1. Navigate to the desired level (Organization, Environment, Application, or Instance)
  2. 2. Go to the Variables tab
  3. 3. Click Add Variable
  4. 4. Enter key and value
  5. 5. Click Save

Variable Naming Conventions

✓ GOOD:
  DATABASE_URL          # Clear, descriptive
  MAX_RETRIES          # SCREAMING_SNAKE_CASE
  FEATURE_NEW_UI       # Boolean feature flag
  API_TIMEOUT_MS       # Include units in name

✗ BAD:
  db                   # Too short, unclear
  Database-URL         # Hyphens not standard
  max retries          # Spaces not allowed
  timeout              # Ambiguous (seconds? milliseconds?)

Updating Variables

Changes to variables require a deployment restart to take effect:

  • Running deployments: Stop and start, or redeploy
  • New deployments: Will automatically use updated values
  • Inheritance changes: Affect all child levels automatically

Deleting Variables

Click the trash icon next to the variable. Be careful - this affects all deployments using this variable.

Managing Secrets

Adding Secrets

  1. 1. Navigate to the desired level
  2. 2. Go to the Secrets tab
  3. 3. Click Add Secret
  4. 4. Enter key and value (value will be masked as you type)
  5. 5. Click Save

⚠️ Once saved, you cannot view the secret value again. If you need to see it, you must delete and recreate it.

Updating Secrets

To update a secret value:

  1. 1. Delete the existing secret
  2. 2. Create a new secret with the same key and new value
  3. 3. Restart or redeploy applications using this secret

Secret Storage

Encryption:

  • • Secrets encrypted at rest using AES-256
  • • Stored separately from variables in secure vault
  • • Decrypted only when injecting into containers
  • • Never logged or displayed in UI/API

Best Practices

DO:

  • ✓ Use secrets for ALL sensitive data (passwords, tokens, keys)
  • ✓ Define common config at organization level (DRY principle)
  • ✓ Override at lower levels only when necessary
  • ✓ Use descriptive, consistent naming (DATABASE_URL, not DB or db_url)
  • ✓ Document non-obvious variables (what they do, valid values)
  • ✓ Include units in names when relevant (TIMEOUT_MS, MAX_SIZE_MB)
  • ✓ Use environment-specific values (prod DB different from staging)
  • ✓ Rotate secrets regularly (API keys, passwords)
  • ✓ Delete unused variables to reduce clutter

DON'T:

  • ✗ Store passwords or keys as variables (use secrets!)
  • ✗ Hardcode values in application code - use variables
  • ✗ Use production secrets in dev/staging environments
  • ✗ Share secrets via email, Slack, or other insecure channels
  • ✗ Commit secrets to git repositories
  • ✗ Use generic names like TEMP, CONFIG, or DATA
  • ✗ Override every variable at every level (defeats inheritance)
  • ✗ Store large files as variables (use volumes or object storage)

Security Guidelines

Access Control

  • • Only organization admins can manage organization-level variables/secrets
  • • Environment maintainers can manage environment-level and below
  • • Application owners can manage application and instance levels
  • • Secrets are write-only - even admins cannot view after creation

Secret Rotation

Regularly rotate secrets to minimize risk:

  • • Database passwords: Every 90 days
  • • API keys: Every 180 days or on team changes
  • • TLS certificates: Before expiration (Let's Encrypt auto-renews)
  • • OAuth tokens: When user leaves team

Audit Trail

SeaGit logs all variable/secret changes:

  • • Who created/updated/deleted
  • • When the change occurred
  • • Which deployments were affected
  • • Previous and new values (variables only, not secrets)

Accessing in Applications

Variables and secrets are injected as environment variables. Access them using your language's standard methods:

Node.js

// Read environment variable
const dbUrl = process.env.DATABASE_URL;
const apiKey = process.env.API_KEY;

// With default fallback
const port = process.env.PORT || 3000;

// Parse numbers
const maxRetries = parseInt(process.env.MAX_RETRIES || '3', 10);

// Parse booleans
const debugMode = process.env.DEBUG === 'true';

Python

import os

# Read environment variable
db_url = os.environ.get('DATABASE_URL')
api_key = os.environ['API_KEY']  # Raises KeyError if missing

# With default fallback
port = int(os.environ.get('PORT', 3000))

# Parse booleans
debug_mode = os.environ.get('DEBUG', 'false').lower() == 'true'

Go

import (
    "os"
    "strconv"
)

// Read environment variable
dbURL := os.Getenv("DATABASE_URL")

// With default fallback
port := os.Getenv("PORT")
if port == "" {
    port = "3000"
}

// Parse numbers
maxRetries, _ := strconv.Atoi(os.Getenv("MAX_RETRIES"))

// Parse booleans
debugMode := os.Getenv("DEBUG") == "true"

Java

// Read environment variable
String dbUrl = System.getenv("DATABASE_URL");

// With default fallback
String port = System.getenv().getOrDefault("PORT", "3000");

// Parse numbers
int maxRetries = Integer.parseInt(
    System.getenv().getOrDefault("MAX_RETRIES", "3")
);

// Parse booleans
boolean debugMode = "true".equals(System.getenv("DEBUG"));

Advanced: Multi-Value Secrets

For complex configuration like JSON service account keys or multi-line certificates:

Option 1: Base64 Encoding (Recommended)

# Encode file to base64
cat service-account.json | base64 > encoded.txt

# Add as secret:
# Key: GCP_SERVICE_ACCOUNT_BASE64
# Value: (paste encoded content)

# In application, decode:
# Node.js
const decoded = Buffer.from(
  process.env.GCP_SERVICE_ACCOUNT_BASE64, 
  'base64'
).toString('utf-8');
const config = JSON.parse(decoded);

# Python
import base64, json
decoded = base64.b64decode(os.environ['GCP_SERVICE_ACCOUNT_BASE64'])
config = json.loads(decoded)

Option 2: Use Kubernetes Secrets (Advanced)

For very large files or complex structures, create Kubernetes secrets directly and mount as files:

# Create Kubernetes secret
kubectl create secret generic app-config \
  --from-file=service-account.json \
  --namespace=production

# Mount in pod (configure in application YAML)
volumes:
  - name: config
    secret:
      secretName: app-config
volumeMounts:
  - name: config
    mountPath: /etc/config
    readOnly: true

# Access in code
const config = require('/etc/config/service-account.json');

API Reference

List Variables

GET /api/v1/organizations/{org_id}/variables

Response:
{
  "variables": [
    {
      "key": "LOG_LEVEL",
      "value": "info",
      "level": "organization",
      "created_at": "2024-01-15T10:00:00Z"
    }
  ]
}

Create Variable

POST /api/v1/environments/{env_id}/variables

{
  "key": "DATABASE_HOST",
  "value": "db.production.local"
}

Response: 201 Created

Create Secret

POST /api/v1/applications/{app_id}/secrets

{
  "key": "API_KEY",
  "value": "sk-1234567890abcdef"
}

Response: 201 Created
Note: value is write-only, cannot be retrieved

Get Effective Configuration

Retrieve merged variables/secrets for a specific instance (with inheritance resolved):

GET /api/v1/instances/{instance_id}/config

Response:
{
  "variables": {
    "LOG_LEVEL": "error",        # From instance (override)
    "DATABASE_HOST": "db.local", # From environment
    "MAX_CONNECTIONS": "100",    # From organization
    "APP_NAME": "api-service"    # From application
  },
  "secrets": {
    "API_KEY": "****",           # Hidden
    "DATABASE_PASSWORD": "****"  # Hidden
  }
}

Troubleshooting

Variable not updating in application

Cause: Variables are injected at container start time

Solution: Restart deployment or redeploy after changing variables

Application crashes with "missing environment variable"

Cause: Required variable not set at any level

Solution: Add the variable at appropriate level, then redeploy

Can't remember secret value

Cause: Secrets are write-only by design

Solution: Generate/retrieve from source (e.g., AWS console for access keys), update secret

Variable showing wrong value in application

Cause: Overridden at a lower level (check inheritance)

Solution: Use "Get Effective Configuration" API to see final merged values