Skip to content

hugobatista/tailscale-jit

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

16 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Tailscale JIT Access πŸ›‘οΈ

Secure, temporary access to Tailscale resources using GitHub Actions.

Grant just-in-time access to your Tailscale-protected infrastructure with GitHub's built-in security and approvals. No persistent permissions needed.

πŸš€ Quick Start

  1. Configure Tailscale ACLs with posture-based access rules (see example)
  2. Fork this GitHub repository or copy the workflow files into your own repository
  3. Configure secrets for Tailscale API access
  4. Trigger access requests via GitHub Actions

Example Grants Configuration

{
  // Define postures that check for custom attributes set by GitHub Actions workflows
  "postures": {
    "posture:jit_ssh_granted": ["custom:ssh_jit_granted == true"],
    "posture:jit_arr_granted": ["custom:arr_jit_granted == true"],
    "posture:jit_monitoring_granted": ["custom:monitoring_jit_granted == true"],
    "posture:jit_admin_granted": ["custom:admin_jit_granted == true"]
  },
  "grants": [
    {
      // example of using posture-based grant for SSH access - can be applied to any service by defining appropriate postures and grants
      "src": ["autogroup:member"],
      "srcPosture": ["posture:jit_ssh_granted"],
      "dst": ["tag:production-server"],
      "ip": ["tcp:22"]
    },
    {
      // example of using the same pattern for access to a web service, like the arr suite - can be applied to any service by defining appropriate postures and grants
      "src": ["autogroup:member"],
      "srcPosture": ["posture:jit_arr_granted"],
      "dst": ["tag:arr-server"],
      "ip": ["tcp:80", "tcp:443", "tcp:6767"]
    },
    {
      // example of using the same pattern for monitoring access - can be applied to any service by defining appropriate postures and grants
      "src": ["autogroup:member"],
      "srcPosture": ["posture:jit_monitoring_granted"],
      "dst": ["tag:monitoring-server"],
      "ip": ["tcp:9090"]
    },
    {
      // example of full access grant - use with caution!
      "src": ["autogroup:member"],
      "srcPosture": ["posture:jit_admin_granted"],
      "dst": ["tag:monitoring-server", "tag:production-server", "tag:arr-server"],
      "ip": ["*"]
    }
  ]
}

✨ Key Features

  • GitHub-Native Security: Leverage GitHub's authentication, secrets, and approval workflows
  • Temporary Access: Grant time-limited access with automatic expiration
  • Device-Level Control: Target specific devices by hostname
  • Bulk Operations: Expire access across all devices when needed
  • Mobile-Friendly: Request access from GitHub Mobile app
  • Telegram Notifications: (Optional) Real-time notifications for access grants and revocations
  • Customizable: Base framework that can be extended with approvers and custom logic
  • Audit Trail: Full logging through GitHub Actions and Tailscale API

πŸ”„ How It Works

  1. Posture Definition: Define Tailscale postures that check for custom attributes (e.g., custom:ssh_jit_granted, custom:arr_jit_granted, custom:monitoring_jit_granted, custom:admin_jit_granted)
  2. Grants: Use srcPosture in grants to restrict access to devices with the required attributes
  3. GitHub Actions: Workflows use Tailscale API to set/remove custom attributes on devices
  4. JIT Access: When attribute is present, posture condition is met, granting access
  5. Access Types: Choose from ssh, arr, monitoring, admin, or all access types. Use "all" to revoke all JIT attributes simultaneously.

πŸ“Š Workflows

Workflow File Description
JIT Access .github/workflows/jit.yml Grants temporary access (ssh, arr, monitoring, or admin) to a specific device by setting the corresponding custom attribute with expiration.
Expire JIT Access (Specific Device) .github/workflows/jit-expire-device.yml Revokes JIT access (ssh, arr, monitoring, admin, or all) from a specific device by removing the corresponding custom attribute(s). Use "all" to revoke all JIT attributes at once.
Expire All JIT Access .github/workflows/jit-expire-all.yml Revokes JIT access (ssh, arr, monitoring, admin, or all) from all devices in the tailnet by removing the corresponding custom attribute(s) where present. Use "all" to revoke all JIT attributes at once.

πŸ› οΈ Setup

Prerequisites

  • GitHub repository with Actions enabled
  • Tailscale OAuth client configured

Tailscale Configuration

  1. Create OAuth Client in Tailscale admin console:

    • Go to Settings β†’ OAuth clients
    • Create client with scopes: devices:core:read, devices:posture_attributes
  2. Define Postures in your tailnet policy file:

    "postures": {
      "posture:jit_ssh_granted": ["custom:ssh_jit_granted == true"],
      "posture:jit_arr_granted": ["custom:arr_jit_granted == true"],
      "posture:jit_monitoring_granted": ["custom:monitoring_jit_granted == true"],
      "posture:jit_admin_granted": ["custom:admin_jit_granted == true"]
    }
  3. Configure Grants to use posture-based access:

    "grants": [
      {
        "src": ["autogroup:member"],
        "srcPosture": ["posture:jit_ssh_granted"],
        "dst": ["tag:secure-resource"],
        "ip": ["tcp:22"]
      },
      {
        "src": ["autogroup:member"],
        "srcPosture": ["posture:jit_arr_granted"],
        "dst": ["tag:arr-server"],
        "ip": ["tcp:80", "tcp:443", "tcp:6767"]
      },
      {
        "src": ["autogroup:member"],
        "srcPosture": ["posture:jit_monitoring_granted"],
        "dst": ["tag:monitoring-server"],
        "ip": ["tcp:9090"]
      },
      {
        "src": ["autogroup:member"],
        "srcPosture": ["posture:jit_admin_granted"],
        "dst": ["tag:monitoring-server", "tag:production-server", "tag:arr-server"],
        "ip": ["*"]
      }
    ]

GitHub Configuration

  1. Add Repository Secrets:

    • TS_OAUTH_CLIENT_ID: Your Tailscale OAuth client ID
    • TS_OAUTH_CLIENT_SECRET: Your Tailscale OAuth client secret
    • TELEGRAM_BOT_TOKEN: (Optional) Telegram bot token for notifications
    • TELEGRAM_CHAT_ID: (Optional) Telegram chat ID for notifications
  2. Set up Telegram Notifications (optional - workflows will work without notifications):

    • Create a Telegram bot via @BotFather
    • Get your bot token from BotFather
    • Create a private Telegram channel or group for notifications
    • Add the bot as an administrator to the channel/group
    • Get the chat ID using methods like sending a message to the channel and checking https://api.telegram.org/bot<YourBOTToken>/getUpdates
    • Set TELEGRAM_BOT_TOKEN and TELEGRAM_CHAT_ID as repository secrets
    • If not configured, workflows will show a warning and continue without notifications
  3. Copy Workflows to .github/workflows/ in your repository

  4. Customize workflows as needed (notification channels, approval requirements, etc.)

πŸ“‹ Usage

Request Access

  • Go to Actions β†’ JIT Access
  • Enter device hostname, duration, and access type (ssh, arr, monitoring, or admin)
  • Click Run workflow

Revoke Access

  • Single Device: Use "Expire JIT Access (Specific Device)"
    • Specify device hostname and access type (ssh, arr, monitoring, admin, or all)
    • Use "all" to revoke all JIT attributes from the device at once
  • All Devices: Use "Expire All JIT Access"
    • Specify access type (ssh, arr, monitoring, admin, or all)
    • Use "all" to revoke all JIT attributes from all devices at once

πŸ§ͺ Running Workflows Locally

Test and debug workflows locally using act, which simulates the GitHub Actions environment on your machine.

Using secret-tool-run + act (recommended)

Use secret-tool-run to load secrets from your system keyring without storing plaintext files on disk.

  1. Install secret-tool-run (see the secret-tool-run README)
  2. Run act through secret-tool-run using file descriptor mode

Example:

secret-tool-run ./bin/act workflow_dispatch \
  --secret-file @SECRETS@ \
  --eventpath event-grant.json \
  -j grant-access \
  -P ubuntu-latest=ghcr.io/catthehacker/ubuntu:act-latest

When prompted the first time, paste your secrets in this format:

TS_OAUTH_CLIENT_ID=your_client_id
TS_OAUTH_CLIENT_SECRET=your_client_secret
TELEGRAM_BOT_TOKEN=your_token (optional)
TELEGRAM_CHAT_ID=your_chat_id (optional)

secret-tool-run stores the secrets in your local keyring. You can check stored entries with secret-tool lookup app <appname> and delete them with secret-tool clear app <appname>.

Using act directly (stores secrets on disk)

  • Install act
  • Create a .secrets file in your repository root with your secrets:
    TS_OAUTH_CLIENT_ID=your_client_id
    TS_OAUTH_CLIENT_SECRET=your_client_secret
    TELEGRAM_BOT_TOKEN=your_token (optional)
    TELEGRAM_CHAT_ID=your_chat_id (optional)
    

Use the event-grant.json file to simulate workflow inputs:

act workflow_dispatch \
  --eventpath event-grant.json \
  --secret-file .secrets \
  -j grant-access \
  -P ubuntu-latest=ghcr.io/catthehacker/ubuntu:act-latest

Parameters:

  • workflow_dispatch: Trigger type (matches the workflow's on: workflow_dispatch)
  • --eventpath event.json: Path to file containing workflow inputs
  • --secret-file .secrets: Path to file with repository secrets
  • -j grant-access: Job ID to run (find in workflow YAML)
  • -P ubuntu-latest=...: Container image for the runner

Example .secrets file

TS_OAUTH_CLIENT_ID=your_client_id
TS_OAUTH_CLIENT_SECRET=your_client_secret
TELEGRAM_BOT_TOKEN=your_token (optional)
TELEGRAM_CHAT_ID=your_chat_id (optional)

Example event.json

{
  "inputs": {
    "source_hostname": "my-server",
    "duration_minutes": "30",
    "access_type": "ssh"
  }
}

🎨 Customization

  • Add Approvals: Enable GitHub environment protection rules
  • Custom Attributes: Extend for VPN, database, or admin access
  • Notifications: Replace Telegram with Slack, Teams, or webhooks
  • Validation: Add time restrictions or device health checks

πŸ”’ Security

  • OAuth with minimal scopes
  • Automatic access expiration
  • Complete audit trails
  • GitHub secrets management

πŸ“š Resources


MIT License

About

Secure just-in-time access to Tailscale-protected infrastructure using GitHub Actions. Leverage GitHub's built-in security, approvals, and audit trails for temporary, auditable network access.

Topics

Resources

License

Stars

Watchers

Forks

Sponsor this project

 

Contributors