Skip to main content

tailscale_rest/models/
tailnet.rs

1//! The tailnet itself: its settings, its OAuth apps, and — for an
2//! organization that has several — the tailnets in it.
3//!
4//! [`Error`] lives here too, for want of anywhere better. It is the shape
5//! every failing call answers with, and `ApiError::describe` is what reads it
6//! in practice; the model is here so the drift test covers it like any other
7//! schema.
8
9use crate::Secret;
10use crate::model;
11use crate::models::KnownValues;
12
13/// Which roles may accept an invitation to another tailnet.
14///
15/// `none` is one of the values rather than the field being absent, so leaving
16/// the setting off is itself a setting.
17pub const ROLES_ALLOWED_TO_JOIN: &[&str] = &["none", "admin", "member"];
18
19pub const KNOWN_VALUES: &[KnownValues] = &[(
20    "TailnetSettings.usersRoleAllowedToJoinExternalTailnets",
21    ROLES_ALLOWED_TO_JOIN,
22)];
23
24model! {
25    /// What a failing call says went wrong.
26    Error {
27        message: "message" => String,
28    }
29
30    /// The tailnet-wide switches.
31    ///
32    /// Most are nullable in the description, where `null` means the tailnet's
33    /// plan does not carry the feature — which is not the same answer as
34    /// `false`, and is why they stay `Option` rather than defaulting.
35    TailnetSettings {
36        /// Stops the policy file being edited in the admin console, so that a
37        /// GitOps or Terraform workflow is the only writer.
38        acls_externally_managed_on: "aclsExternallyManagedOn" => bool,
39        /// Where the admin console points a reader when the above is on.
40        acls_external_link: "aclsExternalLink" => String,
41        devices_approval_on: "devicesApprovalOn" => bool,
42        devices_auto_updates_on: "devicesAutoUpdatesOn" => bool,
43        /// How long a device's key lasts before it must reauthenticate.
44        devices_key_duration_days: "devicesKeyDurationDays" => i64,
45        users_approval_on: "usersApprovalOn" => bool,
46        /// One of [`ROLES_ALLOWED_TO_JOIN`].
47        users_role_allowed_to_join_external_tailnets:
48            "usersRoleAllowedToJoinExternalTailnets" => String,
49        network_flow_logging_on: "networkFlowLoggingOn" => bool,
50        regional_routing_on: "regionalRoutingOn" => bool,
51        /// Whether posture integrations may collect device identity.
52        posture_identity_collection_on: "postureIdentityCollectionOn" => bool,
53        /// Whether devices can be issued HTTPS certificates.
54        https_enabled: "httpsEnabled" => bool,
55    }
56
57    /// An OAuth app, which is a third party a user can grant access to.
58    ///
59    /// Not to be confused with an OAuth client, which is a credential this
60    /// server can hold; see [`crate::credentials::Credentials`].
61    OAuthApp {
62        id: "id" => String,
63        /// 3 to 50 characters of `[A-Za-z0-9._-]`.
64        name: "name" => String,
65        /// At most 300 characters.
66        description: "description" => String,
67        /// Where the authorization code flow may return to. At least one is
68        /// required and each must be `https`.
69        redirect_uris: "redirectURIs" => Vec<String>,
70        /// Must be non-empty.
71        scopes: "scopes" => Vec<String>,
72        /// The device attributes this app may set.
73        allowed_node_attributes: "allowedNodeAttributes" => Vec<String>,
74        /// Sent when the app is created and never again.
75        client_secret: "clientSecret" => Secret,
76        created: "created" => String,
77        updated: "updated" => String,
78    }
79
80    /// Every OAuth app the tailnet has.
81    OAuthAppList as "GET /tailnet/{tailnet}/oauth-apps 200" {
82        oauth_apps: "oauthApps" => Vec<OAuthApp>,
83    }
84
85    /// What creating an OAuth app sends.
86    ///
87    /// The same five fields an update sends, and the description declares them
88    /// through the same shared schemas, so one struct covers both.
89    CreateOAuthAppRequest as "POST /tailnet/{tailnet}/oauth-apps body" {
90        /// 3 to 50 characters of `[A-Za-z0-9._-]`. Required.
91        name: "name" => String,
92        /// At most 300 characters.
93        description: "description" => String,
94        /// Required, at least one, each `https` — or `http` on localhost.
95        redirect_uris: "redirectURIs" => Vec<String>,
96        /// Required and non-empty, as `auth_keys:create` and the like.
97        scopes: "scopes" => Vec<String>,
98        /// Device attributes this app may set, each beginning `custom:`.
99        allowed_node_attributes: "allowedNodeAttributes" => Vec<String>,
100    }
101
102    /// What reconfiguring one sends, which is the same body. The secret is
103    /// neither regenerated nor returned.
104    UpdateOAuthAppRequest as "PUT /tailnet/{tailnet}/oauth-apps/{appId} body"
105        is CreateOAuthAppRequest;
106
107    /// One tailnet belonging to an organization.
108    OrganizationTailnet {
109        id: "id" => String,
110        display_name: "displayName" => String,
111        org_id: "orgId" => String,
112        created_at: "createdAt" => String,
113    }
114
115    /// A page of an organization's tailnets.
116    ListOrganizationTailnetsResponse {
117        tailnets: "tailnets" => Vec<OrganizationTailnet>,
118        /// Opaque, and the way to ask for the next page.
119        cursor: "cursor" => String,
120        /// Across every page, not this one.
121        total_count: "totalCount" => i64,
122    }
123
124    /// What creating a tailnet asks for.
125    CreateOrganizationTailnetRequest {
126        display_name: "displayName" => String,
127    }
128
129    /// An OAuth client scoped to a newly created tailnet, so that the caller
130    /// has a credential for it without a second round trip.
131    TailnetOAuthClient {
132        id: "id" => String,
133        /// Sent once, in the answer that created the tailnet.
134        secret: "secret" => Secret,
135    }
136
137    /// A newly created tailnet, or the one that already had the name.
138    CreateOrganizationTailnetResponse {
139        id: "id" => String,
140        display_name: "displayName" => String,
141        org_id: "orgId" => String,
142        /// The suffix this tailnet's MagicDNS names are built on.
143        dns_name: "dnsName" => String,
144        created_at: "createdAt" => String,
145        oauth_client: "oauthClient" => TailnetOAuthClient,
146        /// `true` where the call matched an existing tailnet rather than
147        /// making one, which is what makes creation safe to repeat.
148        already_exists: "alreadyExists" => bool,
149    }
150}