Skip to content
Open
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: 20 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,10 @@ as your source of truth.
panel](https://login.tailscale.com/admin) and copying down the name next to the
Tailscale logo in the upper left hand corner of the page.

### `api-key`
### `oidc-client-id` and `oidc-audience`

**Optional** An API key authorized for your tailnet. You can get one [in the
admin panel](https://login.tailscale.com/admin/settings/keys).
Either `api-key` or `oauth-client-id` and `oauth-secret` are required.

Please note that API keys will expire in 90 days. Set up a monthly event to
rotate your Tailscale API key, or use an OAuth client.

### `oauth-client-id` and `oauth-secret`

**Optional** The ID and secret for an [OAuth client](https://tailscale.com/kb/1215/oauth-clients)
for your tailnet. The client must have the `acl` scope.
**Required** The OIDC client ID and audience for an [OIDC Credential](https://tailscale.com/kb/1581/workload-identity-federation#configure-federated-identities-in-the-admin-console)
for your tailnet. The credential must have the `policy_file` scope.

Either `api-key` or `oauth-client-id` and `oauth-secret` are required.

Expand All @@ -44,7 +35,7 @@ out to production.

## Getting Started

Set up a new GitHub repository that will contain your tailnet policy file. Open the [Access Controls page of the admin console](https://login.tailscale.com/admin/acls) and copy your policy file to
Set up a new GitHub repository that will contain your tailnet policy file. Open the [Access Controls page of the admin console](https://login.tailscale.com/admin/acls/file) and copy your policy file to
a file in that repo called `policy.hujson`.

If you want to change this name to something else, you will need to add the
Expand All @@ -63,10 +54,13 @@ on:

jobs:
acls:
permissions:
contents: read
id-token: write # required for generating an OIDC token
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5

- name: Fetch version-cache.json
uses: actions/cache@v4
Expand All @@ -81,7 +75,8 @@ jobs:
id: deploy-acl
uses: tailscale/gitops-acl-action@v1
with:
api-key: ${{ secrets.TS_API_KEY }}
oidc-client-id: ${{ secrets.TS_OIDC_CLIENT_ID }}
oidc-audience: ${{ secrets.TS_OIDC_AUDIENCE }}
tailnet: ${{ secrets.TS_TAILNET }}
action: apply

Expand All @@ -90,23 +85,23 @@ jobs:
id: test-acl
uses: tailscale/gitops-acl-action@v1
with:
api-key: ${{ secrets.TS_API_KEY }}
oidc-client-id: ${{ secrets.TS_OIDC_CLIENT_ID }}
oidc-audience: ${{ secrets.TS_OIDC_AUDIENCE }}
tailnet: ${{ secrets.TS_TAILNET }}
action: test
```

Generate a new API key [here](https://login.tailscale.com/admin/settings/keys).
Generate a new credential via [Trust Credentials](https://login.tailscale.com/admin/settings/trust-credentials):

Choose an *OpenID Connect* credential, and set the *Issuer* as `Github`. The Subject should be `repo:<your_org>/<your_repo>:<environment>:*`. ([refer to Github's documentation on the `sub` field](https://docs.github.com/en/actions/reference/security/oidc#example-subject-claims).)

Set a monthly calendar reminder to renew this key because Tailscale does not
currently support API key renewal (this will be updated to support that when
that feature is implemented).
In the *Scopes* step, choose **Policy File: Write** (or *Read* if not using the `apply` action.)

Then open the secrets settings for your repo and add two secrets:
Then open the secrets settings for your repo and add three secrets:

* `TS_API_KEY`: Your Tailscale API key from the earlier step
* `TS_TAILNET`: Your tailnet's name (it's next to the logo on the upper
left-hand corner of the [admin
panel](https://login.tailscale.com/admin/machines))
* `TS_OIDC_CLIENT_ID`: Your Tailscale OIDC Client ID from the earlier step
* `TS_OIDC_AUDIENCE`: Your Tailscale OIDC Audience from the earlier step
* `TS_TAILNET`: Your tailnet's ID/name (it's available on the [admin panel Settings](https://login.tailscale.com/admin/settings/general))

Once you do that, commit the changes and push them to GitHub. You will have CI
automatically test and push changes to your tailnet policy file to Tailscale.
Expand Down
47 changes: 24 additions & 23 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,14 @@ name: "Sync Tailscale ACLs"
description: "Push changes to Tailscale and run ACL tests in CI"
inputs:
tailnet:
description: "Tailnet name (eg. example.com, xe.github, tailscale.org.github)"
description: "Tailnet ID or Name (eg. TCZrp4oabE12CNTRL, example.com, xe.github, tailscale.org.github)"
required: true
oidc-client-id:
description: "Tailscale OIDC Client ID"
required: true
oidc-audience:
description: "Tailscale OIDC Audience"
required: true
api-key:
description: "Tailscale API key"
required: false
oauth-client-id:
description: "Tailscale OAuth ID"
required: false
oauth-secret:
description: "Tailscale OAuth Secret"
required: false
policy-file:
description: "Path to policy file"
required: true
Expand All @@ -23,18 +20,26 @@ inputs:
runs:
using: "composite"
steps:
- name: Check Auth Info Empty
if: ${{ inputs['api-key'] == '' && inputs['oauth-secret'] == '' }}
- name: Generate OIDC JWT from Github Actions
id: get_gh_oidc_token
shell: bash
run: |
echo "::error title=⛔ error hint::API Key or OAuth secret must be specified. Maybe you need to populate it in the Secrets for your workflow, see more in https://docs.github.com/en/actions/security-guides/encrypted-secrets and https://tailscale.com/s/oauth-clients"
exit 1
- name: Check Conflicting Auth Info
if: ${{ inputs['api-key'] != '' && inputs['oauth-secret'] != '' }}
OIDC_JWT=$(curl -H "Authorization: Bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" "${ACTIONS_ID_TOKEN_REQUEST_URL}&audience=${{ inputs.oidc-audience }}" | jq -r '.value')
echo "::add-mask::$OIDC_JWT"
echo "jwt=$OIDC_JWT" >> $GITHUB_OUTPUT

- name: Exchange OIDC JWT with a short-lived Tailscale API Key
id: tailscale_api_key
shell: bash
run: |
echo "::error title=⛔ error hint::only one of API Key or OAuth secret should be specified.
exit 1
RESPONSE=$(curl -X POST https://api.tailscale.com/api/v2/oauth/token-exchange \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "client_id=${{ inputs.oidc-client-id }}" \
-d "jwt=${{ steps.get_gh_oidc_token.outputs.jwt }}")
export ACCESS_TOKEN=$(echo $RESPONSE | jq -r '.access_token')
echo "::add-mask::$ACCESS_TOKEN"
echo "access_token=$ACCESS_TOKEN" >> $GITHUB_OUTPUT

- uses: actions/setup-go@v5
with:
go-version: 1.22.4
Expand All @@ -43,10 +48,6 @@ runs:
- name: Gitops pusher
shell: bash
env:
# gitops-pusher will use OAUTH_ID and OAUTH_SECRET if non-empty,
# otherwise it will use API_KEY.
TS_OAUTH_ID: "${{ inputs.oauth-client-id }}"
TS_OAUTH_SECRET: "${{ inputs.oauth-secret }}"
TS_API_KEY: "${{ inputs.api-key }}"
TS_API_KEY: "${{ steps.tailscale_api_key.outputs.access_token }}"
TS_TAILNET: "${{ inputs.tailnet }}"
run: go run tailscale.com/cmd/gitops-pusher@66aa77416744037baec93206ae212012a2314f83 "--policy-file=${{ inputs.policy-file }}" "${{ inputs.action }}"