Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 22 additions & 23 deletions .devcontainer/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -20,35 +20,34 @@ MOUNT_HOST_GIT_CONFIG=false
# ============================================================================
# 1PASSWORD CLI CONFIGURATION
# ============================================================================
# The 1Password CLI is pre-installed in the container. To authenticate it,
# you need to provide either a Service Account token or Connect Server credentials.

# Option 1: Automatic Service Account Creation (Recommended for small teams)
# Option 1: Service Account Token (Recommended for DevContainers)
# ---------------------------------------------------------------------------
# Enable automatic creation of a 1Password service account when the container starts
# Requires: 1Password CLI installed on host and signed in (op signin completed)
OP_CREATE_SERVICE_ACCOUNT=false

# Configure the automatically created service account:
# Token lifetime (examples: 7d, 30d, 90d, 1y)
OP_SA_EXPIRES_IN=30d

# Restrict to specific vaults (comma-separated, leave empty for all vaults)
# Example: OP_SA_VAULTS=Development,Staging,Production
OP_SA_VAULTS=

# Custom name for the service account (defaults to: devcontainer-<repo>-<timestamp>)
# Leave empty to auto-generate based on repository name
OP_SA_NAME=

# Option 2: Manual Service Account Token
# ---------------------------------------------------------------------------
# If you have an existing service account token, set it here
# Create one with: op service-account create my-dev-account --expires-in 30d
# Service accounts provide secure, scoped access without requiring interactive signin.
#
# To create a service account on your host machine:
# 1. Install 1Password CLI: https://developer.1password.com/docs/cli/get-started
# 2. Sign in to your account: op signin
# 3. Create a service account:
# op service-account create "devcontainer-$(basename $(pwd))" --expires-in 30d
# 4. Copy the token (starts with 'ops_') and paste it below
#
# For vault-specific access (more secure):
# op service-account create "my-dev" --expires-in 30d --vault Development:read_items
#
# The token will be securely passed to the container for CLI authentication.
OP_SERVICE_ACCOUNT_TOKEN=

# Option 3: 1Password Connect Server (For larger teams)
# Option 2: 1Password Connect Server (For Teams/Enterprise)
# ---------------------------------------------------------------------------
# If you have a 1Password Connect Server infrastructure
# Connect Server provides centralized access management for teams.
# Contact your IT admin for these values if using Connect Server.
#
# Server URL (e.g., https://connect.company.com)
OP_CONNECT_HOST=
# Connect token for authentication
OP_CONNECT_TOKEN=

# ============================================================================
Expand Down
7 changes: 7 additions & 0 deletions .github/workflows/build-image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up QEMU
uses: docker/setup-qemu-action@v3

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Log in to the Container registry
uses: docker/login-action@v3
with:
Expand All @@ -54,6 +60,7 @@ jobs:
uses: docker/build-push-action@v5
with:
context: ./docker-image
platforms: linux/amd64,linux/arm64
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
Expand Down
32 changes: 24 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,27 +110,43 @@ staging.example.com

#### 1Password Integration

**Option 1: Service Account** (Recommended)
The 1Password CLI is pre-installed but requires authentication configuration.

**Option 1: Service Account** (Recommended for DevContainers)

Service accounts provide secure, non-interactive authentication perfect for development containers.

```bash
# Create on host
op service-account create devcontainer --expires-in 30d
# Add token to .env
OP_SERVICE_ACCOUNT_TOKEN=ops_...
# On your host machine:
# 1. Install 1Password CLI: https://developer.1password.com/docs/cli/get-started
# 2. Sign in: op signin
# 3. Create a service account:
op service-account create "devcontainer-$(basename $(pwd))" --expires-in 30d

# 4. Copy the token (starts with 'ops_') to .devcontainer/.env:
OP_SERVICE_ACCOUNT_TOKEN=ops_YOUR_TOKEN_HERE

# For vault-specific access (more secure):
op service-account create "my-dev" --expires-in 30d --vault Development:read_items
```

**Option 2: Connect Server**
**Option 2: Connect Server** (For Teams/Enterprise)
```bash
# In .devcontainer/.env:
OP_CONNECT_HOST=https://connect.company.com
OP_CONNECT_TOKEN=...
OP_CONNECT_TOKEN=your-connect-token
```

**Usage in container**:
```bash
# Inject environment variables
# Inject environment variables from 1Password
op run --env-file=prod.env -- npm start

# Read specific secrets
export API_KEY=$(op read "op://vault/item/field")

# Use with git for secure commit signing
op plugin init git
```

## 🏗️ Architecture
Expand Down
155 changes: 28 additions & 127 deletions docker-image/scripts/setup-1password.sh
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
#!/bin/bash
# Setup 1Password CLI in the devcontainer
# This script handles service account token creation and configuration
# This script verifies 1Password CLI authentication status

set -e

echo "🔐 Setting up 1Password CLI..."
echo "🔐 Checking 1Password CLI authentication..."

# Check if we already have a service account token
if [ -n "$OP_SERVICE_ACCOUNT_TOKEN" ]; then
echo "✅ Using existing 1Password service account token"
echo "✅ Using 1Password service account token"
# Test the token
if op vault list &>/dev/null; then
echo "✅ 1Password CLI authenticated successfully"
exit 0
else
echo "⚠️ Existing service account token appears invalid"
echo "⚠️ Service account token appears invalid"
echo " Please verify your OP_SERVICE_ACCOUNT_TOKEN is correct"
fi
fi

# Check for Connect Server configuration (secondary option)
# Check for Connect Server configuration
if [ -n "$OP_CONNECT_HOST" ] && [ -n "$OP_CONNECT_TOKEN" ]; then
echo "✅ Using 1Password Connect Server at $OP_CONNECT_HOST"
# Test the connection
Expand All @@ -27,128 +28,28 @@ if [ -n "$OP_CONNECT_HOST" ] && [ -n "$OP_CONNECT_TOKEN" ]; then
exit 0
else
echo "⚠️ Connect Server authentication failed"
echo " Please verify your OP_CONNECT_HOST and OP_CONNECT_TOKEN are correct"
fi
fi

# If we get here, we need to create a service account token
# Check if the host has 1Password CLI available and authenticated
if [ -n "$OP_CREATE_SERVICE_ACCOUNT" ] && [ "$OP_CREATE_SERVICE_ACCOUNT" = "true" ]; then
echo ""
echo "📝 Attempting to create a new 1Password service account..."
echo ""

# Use environment variables to configure the service account
EXPIRES_IN="${OP_SA_EXPIRES_IN:-30d}" # Default 30 days
VAULTS="${OP_SA_VAULTS:-}" # Comma-separated list of vault names

# Generate a unique name with repository info if not provided
if [ -n "$OP_SA_NAME" ]; then
ACCOUNT_NAME="$OP_SA_NAME"
else
# Try to get repository name from git
REPO_NAME=""
if [ -d "/workspace/.git" ]; then
# Get the repository name from the remote URL
REMOTE_URL=$(git -C /workspace config --get remote.origin.url 2>/dev/null || echo "")
if [ -n "$REMOTE_URL" ]; then
# Extract repo name from URL (works with both HTTPS and SSH URLs)
REPO_NAME=$(basename -s .git "$REMOTE_URL" 2>/dev/null || echo "")
fi
fi

# If we couldn't get repo name, try workspace folder name
if [ -z "$REPO_NAME" ]; then
REPO_NAME=$(basename "/workspace" 2>/dev/null || echo "workspace")
fi

# Create unique name: repo-name-YYYYMMDD-HHMMSS
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
ACCOUNT_NAME="devcontainer-${REPO_NAME}-${TIMESTAMP}"
fi

# Check if we can run op on the host
if ! command -v op &> /dev/null; then
echo "⚠️ 1Password CLI not found on host system"
echo " Please install 1Password CLI on your host to auto-create service accounts"
echo " Or set OP_SERVICE_ACCOUNT_TOKEN manually"
exit 0
fi

# Check if user is signed in on the host
if ! op account list &>/dev/null; then
echo "⚠️ Not signed in to 1Password CLI on host"
echo " Please run 'op signin' on your host first"
echo " Or set OP_SERVICE_ACCOUNT_TOKEN manually"
exit 0
fi

echo "Creating service account with:"
echo " • Name: $ACCOUNT_NAME"
echo " • Expires: $EXPIRES_IN"
if [ -n "$VAULTS" ]; then
echo " • Vaults: $VAULTS"
else
echo " • Vaults: All vaults (no restriction)"
fi

# Build the op command
OP_CMD="op service-account create $ACCOUNT_NAME --expires-in $EXPIRES_IN"

# Add vault restrictions if specified
if [ -n "$VAULTS" ]; then
IFS=',' read -ra VAULT_ARRAY <<< "$VAULTS"
for vault in "${VAULT_ARRAY[@]}"; do
OP_CMD="$OP_CMD --vault $vault:read_items"
done
fi

# Create the service account and capture the token
if SERVICE_ACCOUNT_OUTPUT=$(eval $OP_CMD 2>&1); then
# Extract the token from the output
TOKEN=$(echo "$SERVICE_ACCOUNT_OUTPUT" | grep -oP 'ops_[A-Za-z0-9_-]+' | head -1)

if [ -n "$TOKEN" ]; then
# Save the token to a file in the container
echo "$TOKEN" > /home/node/.op_service_account_token
chmod 600 /home/node/.op_service_account_token

# Export for current session
export OP_SERVICE_ACCOUNT_TOKEN="$TOKEN"

echo ""
echo "✅ Service account created successfully!"
echo " Token saved to container (will persist for this container's lifetime)"
echo ""
echo " To use this token in future containers, add to your host environment:"
echo " export OP_SERVICE_ACCOUNT_TOKEN=\"$TOKEN\""
echo ""
else
echo "⚠️ Failed to extract service account token from output"
fi
else
echo "⚠️ Failed to create service account: $SERVICE_ACCOUNT_OUTPUT"
fi
fi

# Final check - if we still don't have authentication, provide instructions
if ! op vault list &>/dev/null 2>&1; then
echo ""
echo "ℹ️ 1Password CLI is not authenticated. To use it, you can:"
echo ""
echo "Option 1: Create a service account on your host and set the token:"
echo " op service-account create my-dev-account --expires-in 30d"
echo " export OP_SERVICE_ACCOUNT_TOKEN=\"<token>\""
echo ""
echo "Option 2: Use 1Password Connect Server:"
echo " export OP_CONNECT_HOST=\"https://your-connect-server.example.com\""
echo " export OP_CONNECT_TOKEN=\"<your-connect-token>\""
echo ""
echo "Option 3: Enable auto-creation in your next container:"
echo " export OP_CREATE_SERVICE_ACCOUNT=true"
echo " export OP_SA_EXPIRES_IN=7d # Optional: token lifetime"
echo " export OP_SA_VAULTS=Development,Staging # Optional: vault restrictions"
echo ""
else
echo "✅ 1Password CLI is ready to use!"
echo " Example: op run --env-file=.env.prod -- npm start"
fi
# If we get here, 1Password is not configured
echo ""
echo "ℹ️ 1Password CLI is not authenticated. To use it:"
echo ""
echo "Option 1: Create a service account (recommended for devcontainers):"
echo " 1. On your host machine, run:"
echo " op service-account create \"devcontainer-\$(basename \$(pwd))\" --expires-in 30d"
echo " 2. Copy the token (starts with 'ops_')"
echo " 3. Add to your .devcontainer/.env file:"
echo " OP_SERVICE_ACCOUNT_TOKEN=ops_YOUR_TOKEN_HERE"
echo " 4. Rebuild the devcontainer"
echo ""
echo "Option 2: Use 1Password Connect Server (for teams):"
echo " Add to your .devcontainer/.env file:"
echo " OP_CONNECT_HOST=https://your-connect-server.example.com"
echo " OP_CONNECT_TOKEN=your-connect-token"
echo ""
echo "Once configured, you can use commands like:"
echo " op run --env-file=.env.prod -- npm start"
echo " op read \"op://vault/item/field\""
echo ""