Skip to content

Commit

Permalink
[FEAT] Improve tags support (#407)
Browse files Browse the repository at this point in the history
* better tags handling

* better tags handling

* fix

* Apply suggestions from code review

Co-authored-by: Ari Kalfus <[email protected]>

* fix review comments

* tailscale_up_timeout to README

---------

Co-authored-by: Ari Kalfus <[email protected]>
  • Loading branch information
McSim85 and artis3n authored Dec 25, 2023
1 parent bafec71 commit 1de02f4
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 27 deletions.
40 changes: 29 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ In most cases you will use `tailscale_authkey`.

If you are uninstalling Tailscale (`state: absent`), neither `tailscale_authkey` nor `tailscale_up_skip` is required.

If you are authenticating with an OAuth key, you must also set `tailscale_tags` (see below).

### tailscale_authkey

Is **not** required if `tailscale_up_skip` is set to `true`.
Expand All @@ -81,7 +83,7 @@ A Node Authorization key can be generated under your Tailscale account. The role
- OAuth key (`tskey-client-XXX-YYYY`) <https://login.tailscale.com/admin/settings/oauth>

> [!IMPORTANT]
> Using an OAuth key requires additionally setting the following variables: `tailscale_oauth_ephemeral`, `tailscale_oauth_preauthorized`, and `tailscale_oauth_tags`.
> Using an OAuth key requires additionally setting the following variables: `tailscale_tags` (must be provided), `tailscale_oauth_ephemeral` (defailts to `true`) and `tailscale_oauth_preauthorized` (defaults to `false`).
Note that auth keys expire up to a maximum of 90 days after they are generated. OAuth secrets do not expire unless revoked, and the generated OAuth access token expires after 1 hour.

Expand Down Expand Up @@ -111,15 +113,18 @@ Register as an [ephemeral node](https://tailscale.com/kb/1111/ephemeral-nodes),

Skip [manual device approval](https://tailscale.com/kb/1099/device-approval), if `true`.

### tailscale_oauth_tags
### tailscale_tags

> [!NOTE]
> Used only when `tailscale_authkey` is an OAuth key.
**Default**: `[]`

**Default**: `""`
Apply supplied tags to the Tailscale nodes configured by this role (via the `--advertise-tags` flag to `tailscale up`).
For more information, see [What are tags?](https://tailscale.com/kb/1068/acl-tags?q=acl%20tag#what-are-acl-tags)

Registering new nodes using OAuth credentials requires advertising one or more tags.
Tags are required for OAuth clients managing devices.
> [!NOTE]
> Tags are required for OAuth clients (`tailscale_authkey` OAuth key).
Entries should not include `tag:`.
For example, `tailscale_args: ['worker']` translates to `--advertise-tags=tag:worker`.

> Auth keys generated by this OAuth client must assign tags (or tags managed by these tags) to devices they authorize.
Expand Down Expand Up @@ -190,9 +195,11 @@ Only `tailscale up` arguments can be passed in.
> **Do not use this for `--authkey`.**
> Use the `tailscale_authkey` variable instead.
>
> **If authenticating with an OAuth key, do not use this for `--advertise-tags`.**
> Use the `tailscale_oauth_tags` variable instead.
> `--advertise-tags` may be used in this variable if you are not authenticating to Tailscale with OAuth.
> **Do not use this for `--advertise-tags`.**
> Use the `tailscale_tags` variable instead.
>
> **Do not use this for `--timeout`.**
> Use the `tailscale_up_timeout` variable instead.
Any stdout/stderr output from the `tailscale` binary will be printed. Since the tasks move quickly in this section, a 5 second pause is introduced to grant more time for users to realize a message was printed.

Expand All @@ -202,6 +209,16 @@ Stderrs will continue to fail the role's execution.
The sensitive `--authkey` value will be redacted by default.
If you need to view the unredacted value, see [`insecurely_log_authkey`](#insecurely_log_authkey).

### tailscale_up_timeout

**Default**: `120s`

Defines the timeout duration for the `tailscale up` command.

> --timeout duration
>
> maximum amount of time to wait for tailscaled to enter a Running state
### verbose

**Default**: `false`
Expand Down Expand Up @@ -276,7 +293,8 @@ Connect using an OAuth client secret:
vars:
verbose: true
tailscale_authkey: "{{ lookup('env', 'TAILSCALE_OAUTH_CLIENT_SECRET') }}"
tailscale_oauth_tags: "tag:oauth"
tailscale_tags:
- "oauth"
# Optionally, also include:
tailscale_oauth_ephemeral: true
tailscale_oauth_preauthorized: false
Expand Down
6 changes: 4 additions & 2 deletions defaults/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,16 @@ state: latest
tailscale_authkey: ""
# Optional command-line arguments for 'tailscale up'
tailscale_args: ""
# Apply provided tags to node
tailscale_tags: []
# Set timeout for 'tailscale up' command
tailscale_up_timeout: "120s"

# Used for OAuth authentication
# Register as an ephemeral node (recommended)
tailscale_oauth_ephemeral: true
# Skip manual device approval
tailscale_oauth_preauthorized: false
# Required device tags to advertise
tailscale_oauth_tags: ""

# Whether to output debug information during role execution
verbose: false
Expand Down
3 changes: 2 additions & 1 deletion molecule/oauth/converge.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@
name: artis3n.tailscale
vars:
verbose: true
tailscale_oauth_tags: "tag:ci-worker"
tailscale_tags:
- "ci-worker"
39 changes: 28 additions & 11 deletions tasks/install.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,17 +76,12 @@
msg: "Ver: {{ tailscale_version }} Online: {{ tailscale_is_online }}"
when: verbose

- name: Install | Save State
ansible.builtin.template:
src: state.j2
dest: "{{ tailscale_state_folder }}/artis3n-tailscale/state"
owner: "{{ ansible_user_uid }}"
group: "{{ ansible_user_gid }}"
mode: '0644'
register: state_file
- name: Install | Prepend 'tag:' to each item in the list
ansible.builtin.set_fact:
tailscale_prepared_tags: "{{ tailscale_tags | map('regex_replace', '^', 'tag:') | list }}"

# OAuth key starts with 'tskey-client-', auth key starts with 'tskey-auth-', with headscale it can be 'unused'
- name: Install | Create authkey string
- name: Install | Build `tailscale up` arguments strings
ansible.builtin.set_fact:
tailscale_authkey_type: >-
{# Check if the key is an OAuth key #}
Expand All @@ -100,21 +95,43 @@
tailscale_authkey_sting: >-
{# Check if the key is an OAuth key #}
{% if tailscale_authkey.startswith('tskey-client-') %}
{{ tailscale_authkey }}?ephemeral={{ tailscale_oauth_ephemeral | bool }}&preauthorized={{ tailscale_oauth_preauthorized | bool }} --advertise-tags={{ tailscale_oauth_tags | trim }}
{{ tailscale_authkey }}?ephemeral={{ tailscale_oauth_ephemeral | bool }}&preauthorized={{ tailscale_oauth_preauthorized | bool }}
{# Check if the key is not OAuth (regular authkey or unused) #}
{% else %}
{{ tailscale_authkey }}
{% endif %}
tailscale_tags_string: >-
{% if tailscale_tags | length > 0 %}
--advertise-tags={{ tailscale_prepared_tags | join(',') }}
{% endif %}
no_log: "{{ not (insecurely_log_authkey | bool) }}"

- name: Install | Authkey Type
ansible.builtin.debug:
msg: "{{ tailscale_authkey_type | trim }}"
when: verbose

- name: Install | Build the final tailscale_args
ansible.builtin.set_fact:
tailscale_args_string: "{{ tailscale_args }} {{ tailscale_tags_string | trim }} --timeout={{ tailscale_up_timeout | trim }}"

- name: Install | Final `tailscale up` arguments string
ansible.builtin.debug:
msg: "{{ tailscale_args_string | trim }}"
when: verbose

- name: Install | Save State
ansible.builtin.template:
src: state.j2
dest: "{{ tailscale_state_folder }}/artis3n-tailscale/state"
owner: "{{ ansible_user_uid }}"
group: "{{ ansible_user_gid }}"
mode: '0644'
register: state_file

- name: Install | Bring Tailscale Up
become: true
ansible.builtin.command: "tailscale up {{ tailscale_args | trim }} --authkey={{ tailscale_authkey_sting | trim }}"
ansible.builtin.command: "tailscale up {{ tailscale_args_string | trim }} --authkey={{ tailscale_authkey_sting | trim }}"
# Since the auth key is included in this task's output, we do not want to log output
no_log: "{{ not (insecurely_log_authkey | bool) }}"
changed_when: true
Expand Down
18 changes: 18 additions & 0 deletions tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,24 @@
- not tailscale_up_skip
- state != "absent"

- name: Tailscale Tags Required with OAuth Key
ansible.builtin.fail:
msg: "When `tailscale_authkey` is an OAuth key, you must supply one or more tags in `tailscale_tags`."
when:
- tailscale_authkey.startswith('tskey-client-')
- not tailscale_tags
- state != "absent"
- not tailscale_up_skip

- name: Use tailscale_tags instead of tailscale_args for tags
ansible.builtin.debug:
msg: You must use `tailscale_tags` instead of `tailscale_args` to assign tags.
when:
- '"--advertise-tags" in tailscale_args'
- not tailscale_tags
- state != "absent"
- not tailscale_up_skip

- name: Skipping Authentication
ansible.builtin.debug:
msg: You have set 'tailscale_up_skip', so this node will not authenticate to your Tailscale network.
Expand Down
4 changes: 2 additions & 2 deletions tasks/templates/state.j2
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{%- if auth_key_in_state -%}
{{ (tailscale_args + ' --authkey=' + tailscale_authkey) | trim | hash('sha256') }}
{{ (tailscale_args_string + ' --authkey=' + tailscale_authkey) | trim | hash('sha256') }}
{% else %}
{{ tailscale_args | trim | hash('sha256') }}
{{ tailscale_args_string | trim | hash('sha256') }}
{%- endif -%}

0 comments on commit 1de02f4

Please sign in to comment.