dsec Integration

Overview

netapi integrates with dsec (Domain Secrets Manager) for secure secrets management, providing encrypted credential handling across different environments with multiple security layers.

First-Time Setup

Before using dsec, install the shell wrapper functions:

# Add to your shell config
dsec shell-init >> ~/.zshrc       # or ~/.bashrc for bash users
source ~/.zshrc

# Fish shell users
dsec shell-init fish >> ~/.config/fish/config.fish

This installs the secure dsource and dsunsource wrapper functions.

Environment Structure

~/.secrets/
├── .metadata/
│   ├── keys/
│   │   ├── master.age.key       # Age private key (chmod 600)
│   │   ├── master.age.pub       # Age public key
│   │   └── passphrase.age       # Optional passphrase (encrypted)
│   └── audit.log                # Access audit trail
└── environments/
    └── domains/
        ├── d000/                 # Personal domain (nested structure)
        │   ├── dev/
        │   │   ├── network.env.age
        │   │   ├── identity.env.age
        │   │   └── app.env.age
        │   └── prod/
        └── d001/                 # Client domain (flat structure)
            ├── dev.env.age
            └── prod.env.age

Loading Secrets

# Load development network secrets
dsource d000 dev/network

# Load ALL dev secrets
dsource d000 dev

# Clear secrets when done
dsunsource

# Short aliases also available
ds d000 dev/network    # Same as dsource
dsu                    # Same as dsunsource

Legacy: eval Syntax

If you have the wrapper installed, the legacy syntax still works:

eval "$(dsec source d000 dev/network)"
eval "$(dsec unsource)"

Never run $(dsec source …​) without eval - this would expose secrets to the terminal. dsec now blocks this by default (strict mode).

Security Features

Eval Context Protection

dsec uses strict mode by default, which requires the DSEC_EVAL_VERIFIED environment variable to be set. This prevents accidental secret exposure when users mistakenly run:

# WRONG - would expose secrets to terminal (now blocked)
$(dsec source d000 dev/network)

# CORRECT - uses secure wrapper
dsource d000 dev/network

Security Modes

Mode Behavior

strict (default)

Requires DSEC_EVAL_VERIFIED=true. Use the dsource wrapper.

permissive

Allows eval "$(dsec source …​)" without wrapper. Still blocks direct TTY output.

To use permissive mode:

export DSEC_SECURITY_MODE=permissive

Passphrase Protection

Add an additional authentication layer:

# Enable passphrase protection
dsec set-passphrase

# You'll be prompted for passphrase on each secrets load
dsource d000 dev/network
# dsec passphrase: ********

# Disable passphrase
dsec remove-passphrase

# Bypass passphrase for a session
export DSEC_REQUIRE_PASSPHRASE=false

Memory Safety

  • Temporary decrypted content stored in /dev/shm (RAM-backed, never touches disk)

  • Secure deletion uses shred -n 10 (10 overwrite passes)

  • Context managers ensure cleanup on exit/error/interrupt

  • All operations logged to audit trail

Environment Variables

After loading secrets, the following metadata is available:

Variable Description

DSEC_LOADED_DOMAIN

Domain ID (e.g., d000)

DSEC_LOADED_TIER

Tier path (e.g., dev/network)

DSEC_LOADED_COUNT

Number of variables loaded

DSEC_LOADED_TIMESTAMP

ISO8601 timestamp of load

DSEC_LOADED_VARS

Space-separated list of variable names

ENV_NAME

Display name for shell prompts (e.g., D000/DEV/NETWORK)

Python Integration

Direct Usage

from netapi.primitives.config import DsecConfig

# Load from pre-sourced environment
config = DsecConfig.from_env()
host = config.get("ISE_PAN_IP")

# Or decrypt directly (requires age key access)
config = DsecConfig.from_domain("d000", "dev/network")
token = config.require("ISE_API_TOKEN")

# Get all variables with a prefix
ise_vars = config.get_prefixed("ISE_")

Vendor Factory Methods

All vendor clients support environment-based initialization:

from netapi.vendors.cisco.ise import ERSClient, MnTClient

# Clients read from environment variables
ers = ERSClient.from_env()
mnt = MnTClient.from_env()

# Or with explicit config
ers = ERSClient(
    host=config.get("ISE_PAN_IP"),
    token=config.get("ISE_API_TOKEN"),
)

CLI Commands Reference

dsec list                        # List all domains and tiers
dsec init <id> <name>            # Initialize new domain
dsec add <id> <tier> <file>      # Add/update encrypted secrets
dsec edit <id> <tier>            # Edit secrets (decrypts to RAM)
dsec show <id> <tier>            # Display secrets (review only)
dsec load <id> <tier> [dir]      # Decrypt to directory
dsec unload [dir]                # Securely remove decrypted files

# Security commands
dsec shell-init [shell]          # Output shell wrapper functions
dsec set-passphrase              # Enable passphrase protection
dsec remove-passphrase           # Disable passphrase protection

Security Best Practices

  • Always use dsource instead of raw dsec source commands

  • Never commit .env or .age files to git

  • Enable passphrase protection for sensitive environments

  • Use separate credentials per environment (dev/staging/prod)

  • Run dsunsource when done working with secrets

  • Rotate secrets regularly

  • Review the audit log periodically: ~/.secrets/.metadata/audit.log