Tailscale Access Strategy

With Sym and Tailscale you can get the benefit of flexible just-in-time privilege escalations to access SSH hosts on your Tailnet.

Connect Sym with your AWS Secrets Manager

Follow the Manage Secrets with AWS Secrets Manager tutorial to connect your AWS Secrets Manager with the Sym Runtime.

Configure Tailscale Credentials

Create Your API User

We recommend you create a dedicated Tailscale user with ACL management permission.

To do this, use the Tailscale Admin Console. Click the ellipsis menu ("...") on your dedicated Tailscale user and select "Edit Role".

Sym will be managing the ACL on this user's behalf, so we need to give this user the "Network admin" role:

Generate Your API Token

  1. Log in to the Tailscale page as your dedicated user.
  2. Go to Settings -> Keys and generate a new API key. Make sure to save it somewhere, we'll need it soon!

🚧

Tailscale API keys are only valid for 90 days!

You will need to generate a new token after 90 days to keep the Sym + Tailscale integration working. To do so, simply repeat the key generation process and replace the key in AWS Secrets Manager so Sym can use it.

Share your Tailscale API Key with Sym

Follow the Share Secrets with the Sym Runtime tutorial to share your Tailscale API Key with Sym. We recommend using the plain-value secret.

# Note: this snippet only shows the Tailscale specific resources.

# An AWS Secrets Manager Secret to hold your Tailscale API Key. Set the value with:
# aws secretsmanager put-secret-value --secret-id "main/tailscale-api-key" --secret-string "YOUR-TAILSCALE-API-KEY"
resource "aws_secretsmanager_secret" "tailscale_api_key" {
  name        = "sym/main/tailscale-api-key"
  description = "API Key for Sym to call Tailscale APIs"

  # This SymEnv tag is required and MUST match the SymEnv tag in the 
  # aws_iam_policy.secrets_manager_access in your `secrets.tf` file
  tags = {
    SymEnv = local.environment_name
  }
}

# This resources tells Sym how to access your Tailscale API Key.
resource "sym_secret" "tailscale_api_key" {
  # `sym_secrets` is defined in "Manage Secrets with AWS Secrets Manager"
  source_id = sym_secrets.this.id

  # Name of the key in AWS Secrets Manager
  path = aws_secretsmanager_secret.tailscale_api_key.name
}

Add a Tailscale Integration

Define a sym_integration resource with type = tailscale. This integration will reference your Tailscale API Token, and will be referenced in the sym_strategy resource later.

  • external_id: The unique name of your Tailscale network.
  • api_token_secret: A required setting which must be set to the ID of a sym_secret referencing your Tailscale API Key.
resource "sym_integration" "tailscale" {
  type        = "tailscale"
  name        = "main-tailscale-integration"
  external_id = "example.com"  # Your Tailscale network

  settings = {
    api_token_secret = sym_secret.tailscale_api_key.id
  }
}

Add Tailscale Access Targets

Define sym_target resources with type = tailscale_group for all of the Tailscale Groups that you wish to manage access to.

  • group_name: The group you want to give SSH access to. Defined in the "groups" section of your Tailscale Access Controls (Tailscale > Admin > Access Controls > Groups).
resource "sym_target" "tailscale_prod_group" {
  type  = "tailscale_group"
  name  = "main-prod-access"
  label = "Prod SSH Access"

  settings = {
    group_name = "prod"
  }
}

resource "sym_target" "tailscale_staging_group" {
  type  = "tailscale_group"
  name  = "main-staging-access"
  label = "Staging SSH Access"

  settings = {
    group_name = "staging"
  }
}

Add a Tailscale Access Strategy

Define a sym_strategy resource with type = tailscale and include the Tailscale Integration and Tailscale Access Targets you defined above.

resource "sym_strategy" "tailscale" {
  type           = "tailscale"
  name           = "main-tailscale-strategy"
  integration_id = sym_integration.tailscale.id

  # This must be a list of `tailscale_group` sym_target that users can request to be escalated to
  targets = [sym_target.tailscale_prod_group.id, sym_target.tailscale_staging_group.id]

🚧

Sym and Tailscale user matching

By default, Sym will modify Tailscale ACL to add the requester's Slack email address to the Tailscale group. If the Tailscale user's email is different from the email used by Slack, you will need to use the symflow CLI to manage the user identity.

Add the Tailscale Strategy to your Flow

In your sym_flow resource, reference your Tailscale sym_strategy as the strategy_id in your Flow Parameters.

resource "sym_flow" "this" {
  name  = "tailscale-ssh-access"
  label = "Tailscale SSH Access"

	# ... other Flow attributes not shown
  
  params {
    # The strategy this Flow will use to manage access.
    strategy_id = sym_strategy.tailscale.id

    # ... other Flow parameters not shown
  }
}

Full Example

You can find the complete code for this example in our Tailscale SSH Access example.

Example Tailscale ACL Setup

{
  // This is the group that we will add/remove user to/from
	"groups": {
		"group:prod": [],
	},
  // This allow users from the prod group to list Tailnet resources with the "tag:prod".
	"acls": [
		{"action": "accept", "src": ["group:prod"], "dst": ["tag:prod:*"]},
	],
  // This allow users from the prod group to connect to instances with the `tag:prod`
	"ssh": [
		{
			"action": "accept",
			"src":    ["group:prod"],
			"dst":    ["tag:prod"],
			"users":  ["ec2-user"],
		},
	],
	"tagOwners": {
		"tag:prod": ["group:prod"],
	},
}