Skip to main content

tailscale_rest/models/
key.rs

1//! Auth keys, API access tokens, OAuth clients and federated identities.
2//!
3//! The control plane calls all four a "key" and tells them apart by
4//! [`Key::key_type`], so one model covers them and most fields apply to only
5//! some of the four. Which is which is in [`KEY_TYPES`].
6
7use std::collections::BTreeMap;
8
9use crate::Secret;
10use crate::model;
11use crate::models::KnownValues;
12
13/// The kinds of key the description knows.
14///
15/// `auth` registers machines, `client` is an OAuth client, `federated` is a
16/// workload identity, and `api` is an access token — a user's own, or one
17/// minted by either of the other two.
18pub const KEY_TYPES: &[&str] = &["auth", "client", "api", "federated"];
19
20/// What [`KEY_TYPES`] narrows to on the way in.
21///
22/// The description gives three different lists for one field: a response may
23/// say `api`, a create may not ask for one, and an update may not change a key
24/// into an `auth` key. A tool that quoted the response list on a create
25/// parameter would be offering values the control plane rejects.
26pub const CREATE_KEY_TYPES: &[&str] = &["auth", "client", "federated"];
27
28/// What an update accepts, which is narrower still.
29pub const UPDATE_KEY_TYPES: &[&str] = &["client", "federated"];
30
31pub const KNOWN_VALUES: &[KnownValues] = &[("Key.keyType", KEY_TYPES),
32    ("POST /tailnet/{tailnet}/keys body.keyType", CREATE_KEY_TYPES),
33    ("PUT /tailnet/{tailnet}/keys/{keyId} body.keyType", UPDATE_KEY_TYPES),
34];
35
36model! {
37    /// An auth key, an API access token, an OAuth client or a federated
38    /// identity.
39    Key {
40        id: "id" => String,
41        /// The secret itself, sent only in the answer that creates it. There
42        /// is no second chance to read it.
43        key: "key" => Secret,
44        /// One of [`KEY_TYPES`].
45        key_type: "keyType" => String,
46        /// Auth keys only.
47        expiry_seconds: "expirySeconds" => i64,
48        created: "created" => String,
49        updated: "updated" => String,
50        expires: "expires" => String,
51        revoked: "revoked" => String,
52        capabilities: "capabilities" => KeyCapabilities,
53        /// OAuth clients and federated identities: what the tokens they mint
54        /// are allowed to do.
55        scopes: "scopes" => Vec<String>,
56        tags: "tags" => Vec<String>,
57        description: "description" => String,
58        invalid: "invalid" => bool,
59        user_id: "userId" => String,
60        /// Federated identities: the audience the JWT must claim.
61        audience: "audience" => String,
62        /// Federated identities: the issuer whose JWTs are accepted.
63        issuer: "issuer" => String,
64        /// Federated identities: the subject the JWT must claim.
65        subject: "subject" => String,
66        /// Federated identities: claims mapped to values, for narrowing which
67        /// JWTs from the issuer are accepted.
68        custom_claim_rules: "customClaimRules" => BTreeMap<String, String>,
69    }
70
71    /// What a key may do, by resource.
72    KeyCapabilities {
73        /// Populated for auth keys only.
74        devices: "devices" => DeviceCapabilities,
75    }
76
77    /// A key's permissions over devices.
78    DeviceCapabilities as "KeyCapabilities.devices" {
79        create: "create" => CreateCapability,
80    }
81
82    /// What registering a device with this key produces.
83    CreateCapability as "KeyCapabilities.devices.create" {
84        /// A reusable key registers more than one device.
85        reusable: "reusable" => bool,
86        /// An ephemeral device is cleaned up when it goes away.
87        ephemeral: "ephemeral" => bool,
88        /// Devices registered with this key skip admin approval.
89        preauthorized: "preauthorized" => bool,
90        /// The tags every device registered with this key is given.
91        tags: "tags" => Vec<String>,
92    }
93
94    // -----------------------------------------------------------------------
95    // The shapes the routes carry, which the description spells out where they
96    // are used rather than naming in `components/schemas`.
97    // -----------------------------------------------------------------------
98
99    /// Every key the credential may see.
100    KeyList as "GET /tailnet/{tailnet}/keys 200" {
101        keys: "keys" => Vec<Key>,
102    }
103
104    /// What creating a key sends.
105    ///
106    /// Not [`Key`] with the read-only fields dropped: the two disagree about
107    /// `keyType`, which narrows to [`CREATE_KEY_TYPES`] here, and about
108    /// `capabilities`, which a create must send and a listing never returns.
109    CreateKeyRequest as "POST /tailnet/{tailnet}/keys body" {
110        /// One of [`CREATE_KEY_TYPES`]. An `api` token cannot be minted here.
111        key_type: "keyType" => String,
112        /// Up to 50 characters of letters, digits, hyphens and spaces.
113        description: "description" => String,
114        capabilities: "capabilities" => KeyCapabilities,
115        /// Auth keys only; how long the key stays usable.
116        expiry_seconds: "expirySeconds" => i64,
117        /// OAuth clients and federated identities: what their tokens may do.
118        scopes: "scopes" => Vec<String>,
119        /// Required when `scopes` includes `devices:core` or `auth_keys`.
120        tags: "tags" => Vec<String>,
121        /// Federated identities only, all four of these.
122        issuer: "issuer" => String,
123        subject: "subject" => String,
124        audience: "audience" => String,
125        custom_claim_rules: "customClaimRules" => BTreeMap<String, String>,
126    }
127
128    /// What reconfiguring an OAuth client or a federated identity sends.
129    ///
130    /// The same fields as a create minus the three an existing key cannot
131    /// change: its capabilities, its expiry, and being an auth key at all.
132    UpdateKeyRequest as "PUT /tailnet/{tailnet}/keys/{keyId} body" {
133        /// One of [`UPDATE_KEY_TYPES`]: an auth key or an API token cannot be
134        /// reconfigured here.
135        key_type: "keyType" => String,
136        description: "description" => String,
137        scopes: "scopes" => Vec<String>,
138        tags: "tags" => Vec<String>,
139        issuer: "issuer" => String,
140        subject: "subject" => String,
141        audience: "audience" => String,
142        custom_claim_rules: "customClaimRules" => BTreeMap<String, String>,
143    }
144}