Configuration
tsiam is configured via a YAML file. The application searches for configuration in this order:
- Path set in the
TSIAM_CONFIGenvironment variable ./config.yaml(current directory)~/.tsiam/config.yaml/etc/tsiam/config.yaml
When using Docker, mount the
config.yamlfile in/etc/tsiam/config.yaml
Example configuration#
tsnet:
hostname: tsiam
funnel: false
tokens:
lifetime: 5m
allowedAudiences:
- "https://api.example.com"
- "api://AzureADTokenExchange"
- "sts.amazonaws.com"
signingKey:
storage: file
algorithm: ES256
file:
storagePath: /var/lib/tsiam/signing-key.json
logs:
level: infoAuthentication#
When tsiam starts for the first time, it needs to join your Tailnet.
Authentication credentials are only used on first startup or when the node key expires.
You have three options:
Auth key#
Generate a Tailscale auth key in the admin console:
tsnet:
authKey: tskey-auth-xxxOr pass it as the TS_AUTHKEY (alias TS_AUTH_KEY) environment variable.
OAuth2 client#
Create a Tailscale OAuth client in the admin portal, then:
Set the
TS_CLIENT_SECRETenvironment variable to the OAuth client secretAdd
tsnet.advertiseTagsto your config (tags are required for OAuth-based registration):tsnet: advertiseTags: ["tag:tsiam"]
Workload identity federation (OIDC)#
If tsiam itself runs in a cloud environment that provides OIDC tokens (e.g., AWS, Azure, GCP, GitHub Actions), it can join the Tailnet using its own workload identity:
- Set
TS_CLIENT_ID - Set either
TS_ID_TOKEN(provide a token directly) orTS_AUDIENCE(let tsnet request an ID token from a supported provider) - Add
tsnet.advertiseTagsto your config (for example["tag:tsiam"])
Configuration reference#
tsnet#
| Option | Type | Default | Description |
|---|---|---|---|
tsnet.hostname | string | "tsiam" | Hostname for this node on the Tailnet |
tsnet.authKey | string | — | Tailscale auth key for automatic node registration |
tsnet.stateDir | string | — | Directory for tsnet state (defaults to a folder next to the config file) |
tsnet.ephemeral | boolean | false | If true, the node is ephemeral and not persisted in the Tailnet |
tsnet.advertiseTags | list | — | Tags to apply to this node, used for ACL enforcement |
tsnet.funnel | boolean | false | Expose .well-known endpoints via Tailscale Funnel |
tokens#
| Option | Type | Default | Description |
|---|---|---|---|
tokens.lifetime | duration | "5m" | Token lifetime (minimum: 1m, maximum: 1h) |
tokens.allowedAudiences | list | required | Audiences that can be requested; only these values will be issued |
tokens.allowEmptyNodeCapability | boolean | false | If true, nodes without an explicit ACL capability grant can request any globally-allowed audience |
tokens.subjectClaim | string | "nodeId" | Value to use for the JWT sub claim — see below |
tokens.subjectClaim values#
| Value | Description |
|---|---|
"nodeId" (default) | Stable Tailscale node identifier — recommended |
"name" | MagicDNS node name — ⚠ can be reused if the device is removed and re-created |
"capability" | The subject field from the matching Tailscale ACL grant, allowing multiple nodes to share one workload identity |
signingKey#
| Option | Type | Default | Description |
|---|---|---|---|
signingKey.storage | string | "file" | Storage backend: file, memory, AzureKeyVaultKeys, AzureKeyVaultSecrets |
signingKey.algorithm | string | "ES256" | Signing algorithm: RS256, ES256, ES384, ES512, EdDSA |
File storage (signingKey.storage: file):
| Option | Type | Default | Description |
|---|---|---|---|
signingKey.file.storagePath | string | required | Path to store the signing key (not encrypted on disk) |
Azure Key Vault Keys (signingKey.storage: AzureKeyVaultKeys):
| Option | Type | Default | Description |
|---|---|---|---|
signingKey.azureKeyVaultKeys.vaultUrl | string | required | Azure Key Vault URL (e.g. https://myvault.vault.azure.net/) |
signingKey.azureKeyVaultKeys.keyName | string | required | Name of the key used for wrapping/unwrapping |
signingKey.azureKeyVaultKeys.storagePath | string | required | Path to store the wrapped signing key on disk |
signingKey.azureKeyVaultKeys.tenantId | string | — | Azure AD tenant ID (uses DefaultAzureCredential if empty) |
signingKey.azureKeyVaultKeys.clientId | string | — | Azure AD application client ID |
signingKey.azureKeyVaultKeys.clientSecret | string | — | Azure AD application client secret |
Azure Key Vault Secrets (signingKey.storage: AzureKeyVaultSecrets):
| Option | Type | Default | Description |
|---|---|---|---|
signingKey.azureKeyVaultSecrets.vaultUrl | string | required | Azure Key Vault URL |
signingKey.azureKeyVaultSecrets.secretName | string | required | Name of the secret storing the signing key |
signingKey.azureKeyVaultSecrets.tenantId | string | — | Azure AD tenant ID |
signingKey.azureKeyVaultSecrets.clientId | string | — | Azure AD application client ID |
signingKey.azureKeyVaultSecrets.clientSecret | string | — | Azure AD application client secret |
logs#
| Option | Type | Default | Description |
|---|---|---|---|
logs.level | string | "info" | Log level: debug, info, warn, error |
logs.omitHealthChecks | boolean | true | Suppress log lines for /healthz requests |
logs.json | boolean | auto | Emit JSON-formatted logs (defaults to true when no TTY is attached) |