Documentation
¶
Overview ¶
Package firezone provides a hand-written Go client for the Firezone REST API (https://www.firezone.dev).
Construct a Client with NewClient, then call methods on its resource services (Sites, Resources, Policies, Groups, Actors, and Gateways nested under Sites):
client, err := firezone.NewClient("https://api.firezone.dev", token)
site, err := client.Sites.Create(ctx, &firezone.CreateSiteRequest{Name: "primary-dc"})
The API is currently unversioned - baseURL is the bare API host, with no path prefix of any kind. (URL path versioning was tried and rolled back before shipping; if it returns, it'll live in exactly one place here rather than every call site.)
A Client is safe for concurrent use by multiple goroutines.
Update requests are merge-patch: a field left at its zero value is omitted and keeps its current value on the server. Fields the API allows to be null are typed Null so they can be cleared as well as set - see Clear and Set.
Index ¶
- Constants
- Variables
- func IsConflict(err error) bool
- func IsForbidden(err error) bool
- func IsNotFound(err error) bool
- func IsRateLimited(err error) bool
- func IsUnauthorized(err error) bool
- func IsValidation(err error) bool
- func String(s string) *string
- type APIError
- type Actor
- type ActorListOptions
- type ActorType
- type ActorsService
- func (s *ActorsService) Create(ctx context.Context, req *CreateActorRequest) (*Actor, error)
- func (s *ActorsService) Delete(ctx context.Context, id string) error
- func (s *ActorsService) Disable(ctx context.Context, id string) (*Actor, error)
- func (s *ActorsService) Enable(ctx context.Context, id string) (*Actor, error)
- func (s *ActorsService) Get(ctx context.Context, id string) (*Actor, error)
- func (s *ActorsService) List(ctx context.Context, opts *ActorListOptions) (*Page[Actor], error)
- func (s *ActorsService) Update(ctx context.Context, id string, req *UpdateActorRequest) (*Actor, error)
- type AuthProvider
- type AuthProviderListOptions
- type Client
- type ClientDevice
- type ClientListOptions
- type ClientsService
- func (s *ClientsService) Delete(ctx context.Context, id string) error
- func (s *ClientsService) Get(ctx context.Context, id string) (*ClientDevice, error)
- func (s *ClientsService) List(ctx context.Context, opts *ClientListOptions) (*Page[ClientDevice], error)
- func (s *ClientsService) Unverify(ctx context.Context, id string) (*ClientDevice, error)
- func (s *ClientsService) Update(ctx context.Context, id string, req *UpdateClientRequest) (*ClientDevice, error)
- func (s *ClientsService) Verify(ctx context.Context, id string) (*ClientDevice, error)
- type Condition
- type ConditionOperator
- type ConditionProperty
- type CreateActorRequest
- type CreateGroupRequest
- type CreatePolicyRequest
- type CreateResourceRequest
- type CreateSiteRequest
- type DirectoryListOptions
- type EmailOTPAuthProvider
- type EmailOTPAuthProvidersService
- type EntraAuthProvider
- type EntraAuthProvidersService
- type EntraDirectoriesService
- type EntraDirectory
- type Filter
- type FilterProtocol
- type Gateway
- type GatewayListOptions
- type GatewaysService
- func (s *GatewaysService) Delete(ctx context.Context, id string) error
- func (s *GatewaysService) Get(ctx context.Context, id string) (*Gateway, error)
- func (s *GatewaysService) List(ctx context.Context, opts *GatewayListOptions) (*Page[Gateway], error)
- func (s *GatewaysService) Provision(ctx context.Context, req *ProvisionGatewayRequest) (*ProvisionedGateway, error)
- func (s *GatewaysService) RotateToken(ctx context.Context, id string) (*RotatedGatewayToken, error)
- func (s *GatewaysService) Update(ctx context.Context, id string, req *UpdateGatewayRequest) (*Gateway, error)
- type GoogleAuthProvider
- type GoogleAuthProvidersService
- type GoogleDirectoriesService
- type GoogleDirectory
- type Group
- type GroupListOptions
- type GroupMember
- type GroupsService
- func (s *GroupsService) Create(ctx context.Context, req *CreateGroupRequest) (*Group, error)
- func (s *GroupsService) Delete(ctx context.Context, id string) error
- func (s *GroupsService) Get(ctx context.Context, id string) (*Group, error)
- func (s *GroupsService) List(ctx context.Context, opts *GroupListOptions) (*Page[Group], error)
- func (s *GroupsService) Memberships(groupID string) *MembershipsService
- func (s *GroupsService) Update(ctx context.Context, id string, req *UpdateGroupRequest) (*Group, error)
- type IPStack
- type ListOptions
- type MembershipsService
- type Null
- type OIDCAuthProvider
- type OIDCAuthProvidersService
- type OktaAuthProvider
- type OktaAuthProvidersService
- type OktaDirectoriesService
- type OktaDirectory
- type Option
- type Page
- type PageMetadata
- type PoliciesService
- func (s *PoliciesService) Create(ctx context.Context, req *CreatePolicyRequest) (*Policy, error)
- func (s *PoliciesService) Delete(ctx context.Context, id string) error
- func (s *PoliciesService) Disable(ctx context.Context, id string) (*Policy, error)
- func (s *PoliciesService) Enable(ctx context.Context, id string) (*Policy, error)
- func (s *PoliciesService) Get(ctx context.Context, id string) (*Policy, error)
- func (s *PoliciesService) List(ctx context.Context, opts *PolicyListOptions) (*Page[Policy], error)
- func (s *PoliciesService) Update(ctx context.Context, id string, req *UpdatePolicyRequest) (*Policy, error)
- type Policy
- type PolicyListOptions
- type PoolMember
- type PoolMembersService
- type ProvisionGatewayRequest
- type ProvisionedGateway
- type Resource
- type ResourceListOptions
- type ResourceType
- type ResourcesService
- func (s *ResourcesService) Create(ctx context.Context, req *CreateResourceRequest) (*Resource, error)
- func (s *ResourcesService) Delete(ctx context.Context, id string) error
- func (s *ResourcesService) Get(ctx context.Context, id string) (*Resource, error)
- func (s *ResourcesService) List(ctx context.Context, opts *ResourceListOptions) (*Page[Resource], error)
- func (s *ResourcesService) PoolMembers(resourceID string) *PoolMembersService
- func (s *ResourcesService) Update(ctx context.Context, id string, req *UpdateResourceRequest) (*Resource, error)
- type RotatedGatewayToken
- type Site
- type SiteListOptions
- type SitesService
- func (s *SitesService) Create(ctx context.Context, req *CreateSiteRequest) (*Site, error)
- func (s *SitesService) Delete(ctx context.Context, id string) error
- func (s *SitesService) Gateways(siteID string) *GatewaysService
- func (s *SitesService) Get(ctx context.Context, id string) (*Site, error)
- func (s *SitesService) List(ctx context.Context, opts *SiteListOptions) (*Page[Site], error)
- func (s *SitesService) Update(ctx context.Context, id string, req *UpdateSiteRequest) (*Site, error)
- type UpdateActorRequest
- type UpdateClientRequest
- type UpdateGatewayRequest
- type UpdateGroupRequest
- type UpdatePolicyRequest
- type UpdateResourceRequest
- type UpdateSiteRequest
Examples ¶
Constants ¶
const Version = "0.1.0"
Version is this SDK's released version, following semantic versioning. It is sent as part of the default User-Agent, so a Firezone operator can tell which client version a request came from.
It is a constant rather than something read from build info, because build info reports "(devel)" whenever the module is built rather than consumed. Bump it as part of cutting a release - see CONTRIBUTING.md.
Variables ¶
var ErrMissingID = errors.New("must not be empty")
ErrMissingID is returned when a method is called with an empty or otherwise unusable resource ID. Test for it with errors.Is:
if errors.Is(err, firezone.ErrMissingID) { ... }
It is returned before any request is made, so an ID that came from unpopulated config fails loudly rather than being sent as an empty path segment - which would silently address the collection endpoint instead (GET /sites rather than GET /sites/{id}).
var ErrNilRequest = errors.New("request must not be nil")
ErrNilRequest is returned when a Create or Update method is called with a nil request body. Test for it with errors.Is:
if errors.Is(err, firezone.ErrNilRequest) { ... }
It is returned before any request is made. Without it a nil request encodes as {"site": null} rather than being caught: v is an any holding a typed nil pointer, so a plain v == nil check is false and json.Marshal happily writes the null.
Functions ¶
func IsConflict ¶
IsConflict reports whether err is an *APIError with StatusCode 409.
The API returns 409 from a single endpoint - creating a token for a Gateway that already has one - which this SDK does not wrap, for the reasons in the GatewaysService doc comment. Most things that read like conflicts, a duplicate name among them, come back as 422 validation errors instead, so reach for IsValidation first.
func IsForbidden ¶
IsForbidden reports whether err is an *APIError with StatusCode 403.
func IsNotFound ¶
IsNotFound reports whether err is an *APIError with StatusCode 404.
func IsRateLimited ¶
IsRateLimited reports whether err is an *APIError with StatusCode 429.
func IsUnauthorized ¶
IsUnauthorized reports whether err is an *APIError with StatusCode 401.
func IsValidation ¶
IsValidation reports whether err is an *APIError with StatusCode 422.
Example ¶
The API reports a duplicate name as a validation error rather than a conflict, with the offending field named in ValidationErrors.
package main
import (
"context"
"errors"
"fmt"
firezone "github.com/firezone/firezone-go"
)
func main() {
var client *firezone.Client // see [NewClient]
_, err := client.Sites.Create(context.Background(), &firezone.CreateSiteRequest{Name: "primary-dc"})
if firezone.IsValidation(err) {
var apiErr *firezone.APIError
if errors.As(err, &apiErr) {
for field, messages := range apiErr.ValidationErrors {
fmt.Printf("%s: %v\n", field, messages)
}
}
}
}
Output:
func String ¶
String returns a pointer to s. Useful for optional string fields (e.g. GroupListOptions.DirectoryID) where a plain string's zero value can't distinguish "not set" from "set to the empty string".
Types ¶
type APIError ¶
type APIError struct {
// StatusCode is the HTTP status code of the response.
StatusCode int
// Type is the RFC 9457 problem type URI. The API always returns
// "about:blank".
Type string
// Title is a short, human-readable summary of the problem, derived
// from the HTTP status code (e.g. "Not Found").
Title string
// Detail is a human-readable explanation specific to this occurrence
// of the problem.
Detail string
// ValidationErrors maps field names to validation failure messages.
// Populated only when StatusCode is 422.
ValidationErrors map[string][]string
// RetryAfter is how long to wait before retrying, parsed from the
// Retry-After response header. Populated only when StatusCode is 429.
RetryAfter time.Duration
}
APIError represents an RFC 9457 (Problem Details for HTTP APIs) error response from the Firezone API.
type Actor ¶
type Actor struct {
ID string `json:"id"`
Name string `json:"name"`
Type ActorType `json:"type"`
Email string `json:"email,omitempty"`
AllowEmailOTPSignIn bool `json:"allow_email_otp_sign_in"`
IsDisabled bool `json:"is_disabled"`
LastSeenAt *time.Time `json:"last_seen_at,omitempty"`
CreatedByDirectoryID string `json:"created_by_directory_id,omitempty"`
InsertedAt time.Time `json:"inserted_at"`
UpdatedAt time.Time `json:"updated_at"`
}
Actor is a Firezone Actor - a user, admin, or service account.
func (*Actor) IsSynced ¶
IsSynced reports whether the Actor was created by an identity provider directory sync, and so is owned by the IdP rather than by this API. It mirrors Group.IsSynced.
Unlike a synced Group, a synced Actor is not wholly read-only here - but its existence and identity are the directory's to decide, so tooling that adopts an existing account should treat it as discovered rather than managed.
type ActorListOptions ¶
type ActorListOptions struct {
ListOptions
// Name filters to Actors with this exact name.
Name string
// Email filters to Actors with this exact email.
Email string
// Type filters to Actors of this type. Unlike [CreateActorRequest]
// and [UpdateActorRequest], "api_client" is a valid filter value
// here - it just can't be created or updated via the API.
Type ActorType
}
ActorListOptions extends ListOptions with Actors-specific filters.
type ActorType ¶
type ActorType string
ActorType is the type of a Firezone Actor. api_client is intentionally not offered as a constant here: it cannot be created, updated, or otherwise managed via this API (the API returns 422 if you try), since api_client actors are how API tokens themselves are issued.
type ActorsService ¶
type ActorsService struct {
// contains filtered or unexported fields
}
ActorsService manages Actors.
func (*ActorsService) Create ¶
func (s *ActorsService) Create(ctx context.Context, req *CreateActorRequest) (*Actor, error)
Create creates a new Actor.
func (*ActorsService) Delete ¶
func (s *ActorsService) Delete(ctx context.Context, id string) error
Delete deletes an Actor.
func (*ActorsService) Disable ¶
Disable disables an Actor, immediately revoking all of its active Client tokens and portal sessions. Returns 403 Forbidden if id is the authenticated actor itself.
This is a convenience wrapper over ActorsService.Update; the API has no dedicated disable endpoint.
func (*ActorsService) Enable ¶
Enable enables a disabled Actor. Idempotent - enabling an already-enabled Actor is a no-op.
This is a convenience wrapper over ActorsService.Update; the API has no dedicated enable endpoint.
func (*ActorsService) List ¶
func (s *ActorsService) List(ctx context.Context, opts *ActorListOptions) (*Page[Actor], error)
List returns a page of Actors. Pass nil for opts to use the API's default page size and no filters.
func (*ActorsService) Update ¶
func (s *ActorsService) Update(ctx context.Context, id string, req *UpdateActorRequest) (*Actor, error)
Update updates an Actor.
type AuthProvider ¶
type AuthProvider struct {
ID string `json:"id"`
AccountID string `json:"account_id"`
Name string `json:"name"`
Issuer string `json:"issuer"`
Context string `json:"context"`
// ClientSessionLifetimeSecs and PortalSessionLifetimeSecs are how
// long a sign-in through this provider stays valid on a Client
// device and in the admin portal respectively.
//
// Both are nil when the provider sets no override and Firezone's own
// defaults apply, which is the usual case - the columns have no
// database default, so a provider that has never had them configured
// stores null. They are pointers for that reason: a plain int would
// decode null to 0, which reads as "sessions expire immediately"
// rather than "not configured".
//
// The spec marks these nullable only on the Entra provider, but the
// underlying schema is identical for all five, so treat every one of
// them as nullable.
ClientSessionLifetimeSecs *int `json:"client_session_lifetime_secs,omitempty"`
PortalSessionLifetimeSecs *int `json:"portal_session_lifetime_secs,omitempty"`
IsDisabled bool `json:"is_disabled"`
InsertedAt time.Time `json:"inserted_at"`
UpdatedAt time.Time `json:"updated_at"`
}
AuthProvider is the state every authentication provider type shares. Each concrete type embeds it and adds its own fields.
Auth providers are read-only through this API: they are configured in the Firezone dashboard, which owns the OAuth/OIDC secrets involved. The Policy condition property "auth_provider_id" takes these IDs.
type AuthProviderListOptions ¶
type AuthProviderListOptions struct {
ListOptions
// Name filters to providers with this exact name, as shown in the
// dashboard's authentication settings.
Name string
}
AuthProviderListOptions extends ListOptions with the filters every auth provider list endpoint accepts. Shared across the five types, which expose the same filter surface.
type Client ¶
type Client struct {
// Sites manages Sites and, nested under them, Gateways.
Sites *SitesService
// Resources manages Resources.
Resources *ResourcesService
// Policies manages Policies.
Policies *PoliciesService
// Groups manages Groups and, nested under them, memberships.
Groups *GroupsService
// Actors manages Actors.
Actors *ActorsService
// ClientDevices manages Client devices. Named for [ClientDevice],
// since Clients is too easily confused with this type itself.
ClientDevices *ClientsService
// EmailOTPAuthProviders reads Email OTP auth providers (read-only).
EmailOTPAuthProviders *EmailOTPAuthProvidersService
// OIDCAuthProviders reads generic OIDC auth providers (read-only).
OIDCAuthProviders *OIDCAuthProvidersService
// GoogleAuthProviders reads Google Workspace auth providers
// (read-only).
GoogleAuthProviders *GoogleAuthProvidersService
// EntraAuthProviders reads Microsoft Entra auth providers
// (read-only).
EntraAuthProviders *EntraAuthProvidersService
// OktaAuthProviders reads Okta auth providers (read-only).
OktaAuthProviders *OktaAuthProvidersService
// EntraDirectories reads Microsoft Entra directory connections
// (read-only).
EntraDirectories *EntraDirectoriesService
// GoogleDirectories reads Google Workspace directory connections
// (read-only).
GoogleDirectories *GoogleDirectoriesService
// OktaDirectories reads Okta directory connections (read-only).
OktaDirectories *OktaDirectoriesService
// contains filtered or unexported fields
}
Client is a Firezone REST API client.
A Client is safe for concurrent use by multiple goroutines: it holds no mutable state once NewClient returns, and each request builds its own URL and body.
func NewClient ¶
NewClient constructs a Firezone API client. baseURL is the bare API host (e.g. "https://api.firezone.dev") - do not include a version segment. token is the Bearer token for an api_client actor.
Requests go through an *http.Client private to this SDK, and each attempt is bounded by defaultRequestTimeout. Pass WithHTTPClient to supply your own client and WithRequestTimeout to change the bound.
Example ¶
package main
import (
"context"
"fmt"
"log"
"os"
firezone "github.com/firezone/firezone-go"
)
func main() {
client, err := firezone.NewClient("https://api.firezone.dev", os.Getenv("FIREZONE_TOKEN"))
if err != nil {
// Only a malformed base URL gets here - it must carry an
// http/https scheme and a host, and no query or fragment.
log.Fatal(err)
}
site, err := client.Sites.Create(context.Background(), &firezone.CreateSiteRequest{
Name: "primary-dc",
})
if err != nil {
log.Fatal(err)
}
fmt.Println(site.Name)
}
Output:
type ClientDevice ¶
type ClientDevice struct {
ID string `json:"id"`
FirezoneID string `json:"firezone_id"`
ActorID string `json:"actor_id"`
Name string `json:"name"`
IPv4 string `json:"ipv4"`
IPv6 string `json:"ipv6"`
Online bool `json:"online"`
PublicKey string `json:"public_key,omitempty"`
Hostname string `json:"hostname,omitempty"`
DeviceSerial string `json:"device_serial,omitempty"`
DeviceUUID string `json:"device_uuid,omitempty"`
// VerifiedAt is nil until an admin verifies the device. Policies can
// require verification via the client_verified condition property.
VerifiedAt *time.Time `json:"verified_at,omitempty"`
// LastSeenAt is nil for a Client that has enrolled but never
// connected.
LastSeenAt *time.Time `json:"last_seen_at,omitempty"`
LastSeenVersion string `json:"last_seen_version,omitempty"`
LastSeenRemoteIP string `json:"last_seen_remote_ip,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
ClientDevice is a Firezone Client - an enrolled end-user device.
The API calls this a "Client", but Client is already this SDK's own API client type, so the device concept carries the Device suffix here.
Client devices are not created through this API: a device registers itself when it first connects. They can be read, renamed, verified, and deleted, but never provisioned - so there is no CreateClientRequest.
type ClientListOptions ¶
type ClientListOptions struct {
ListOptions
// Name filters to Clients with this exact name. Names are not
// unique, so this can still match more than one.
Name string
// FirezoneID filters to Clients with this exact Firezone ID. Unique
// per actor rather than per account, so this too can match more than
// one - though in practice rarely does.
FirezoneID string
}
ClientListOptions extends ListOptions with Clients-specific filters.
type ClientsService ¶
type ClientsService struct {
// contains filtered or unexported fields
}
ClientsService manages Clients.
func (*ClientsService) Delete ¶
func (s *ClientsService) Delete(ctx context.Context, id string) error
Delete deletes a Client, unenrolling the device.
func (*ClientsService) Get ¶
func (s *ClientsService) Get(ctx context.Context, id string) (*ClientDevice, error)
Get fetches a single Client by ID.
func (*ClientsService) List ¶
func (s *ClientsService) List(ctx context.Context, opts *ClientListOptions) (*Page[ClientDevice], error)
List returns a page of Clients. Pass nil for opts to use the API's default page size and no filters.
func (*ClientsService) Unverify ¶
func (s *ClientsService) Unverify(ctx context.Context, id string) (*ClientDevice, error)
Unverify clears a Client's verification.
func (*ClientsService) Update ¶
func (s *ClientsService) Update(ctx context.Context, id string, req *UpdateClientRequest) (*ClientDevice, error)
Update renames a Client.
func (*ClientsService) Verify ¶
func (s *ClientsService) Verify(ctx context.Context, id string) (*ClientDevice, error)
Verify marks a Client as admin-verified, satisfying the client_verified Policy condition.
type Condition ¶
type Condition struct {
Property ConditionProperty `json:"property"`
Operator ConditionOperator `json:"operator"`
Values []string `json:"values"`
}
Condition restricts when a Policy grants access. All Conditions on a Policy must evaluate to true for access to be granted.
Which Operators are valid, and how Values is interpreted, depends on Property:
- ConditionPropertyRemoteIPLocationRegion with is_in / is_not_in: Values are ISO 3166-1 alpha-2 country codes, e.g. "US", "CA".
- ConditionPropertyRemoteIP with is_in_cidr / is_not_in_cidr: Values are CIDR ranges, IPv4 or IPv6.
- ConditionPropertyAuthProviderID with is_in / is_not_in: Values are authentication provider IDs (UUIDs).
- ConditionPropertyCurrentUTCDatetime with is_in_day_of_week_time_ranges: each value is a "DAY/TIME_RANGES/TIMEZONE" string - see ConditionOperatorIsInDayOfWeekTimeRanges.
- ConditionPropertyClientVerified with is: Values is a single-element list holding "true" or "false".
type ConditionOperator ¶
type ConditionOperator string
ConditionOperator is the comparison a policy Condition applies between the subject property and Values. Which operators are valid depends on Property - see the API's policy schema documentation.
const ( ConditionOperatorIsIn ConditionOperator = "is_in" ConditionOperatorIsNotIn ConditionOperator = "is_not_in" ConditionOperatorIsInCIDR ConditionOperator = "is_in_cidr" ConditionOperatorIsNotInCIDR ConditionOperator = "is_not_in_cidr" // ConditionOperatorIsInDayOfWeekTimeRanges matches when the current // time falls inside one of the given weekly windows. Each value is a // "DAY/TIME_RANGES/TIMEZONE" string, where DAY is one of M T W R F S // U (Monday through Sunday), TIME_RANGES is a comma-separated list of // HH:MM-HH:MM ranges, and TIMEZONE is an IANA timezone name - for // example "M/09:00-17:00/America/New_York". // // All three segments are required; the API rejects a value with no // timezone. Days are specified one value per day, so a Monday-Friday // window is five values, not one. ConditionOperatorIsInDayOfWeekTimeRanges ConditionOperator = "is_in_day_of_week_time_ranges" ConditionOperatorIs ConditionOperator = "is" )
ConditionOperator values.
type ConditionProperty ¶
type ConditionProperty string
ConditionProperty is the subject property a policy Condition evaluates.
const ( ConditionPropertyRemoteIPLocationRegion ConditionProperty = "remote_ip_location_region" ConditionPropertyRemoteIP ConditionProperty = "remote_ip" ConditionPropertyAuthProviderID ConditionProperty = "auth_provider_id" ConditionPropertyCurrentUTCDatetime ConditionProperty = "current_utc_datetime" ConditionPropertyClientVerified ConditionProperty = "client_verified" )
ConditionProperty values.
type CreateActorRequest ¶
type CreateActorRequest struct {
Name string `json:"name"`
Type ActorType `json:"type"`
Email string `json:"email,omitempty"`
AllowEmailOTPSignIn *bool `json:"allow_email_otp_sign_in,omitempty"`
}
CreateActorRequest is the request body for ActorsService.Create.
type CreateGroupRequest ¶
type CreateGroupRequest struct {
Name string `json:"name"`
}
CreateGroupRequest is the request body for GroupsService.Create.
type CreatePolicyRequest ¶
type CreatePolicyRequest struct {
GroupID string `json:"group_id"`
ResourceID string `json:"resource_id"`
Description string `json:"description,omitempty"`
FlowLogUploadsEnabled *bool `json:"flow_log_uploads_enabled,omitempty"`
Conditions []Condition `json:"conditions,omitempty"`
}
CreatePolicyRequest is the request body for PoliciesService.Create.
type CreateResourceRequest ¶
type CreateResourceRequest struct {
Name string `json:"name"`
Type ResourceType `json:"type"`
Address string `json:"address,omitempty"`
AddressDescription string `json:"address_description,omitempty"`
IPStack IPStack `json:"ip_stack,omitempty"`
SiteID string `json:"site_id,omitempty"`
Filters []Filter `json:"filters,omitempty"`
}
CreateResourceRequest is the request body for ResourcesService.Create.
type CreateSiteRequest ¶
type CreateSiteRequest struct {
Name string `json:"name"`
}
CreateSiteRequest is the request body for SitesService.Create.
type DirectoryListOptions ¶
type DirectoryListOptions struct {
ListOptions
// Name filters to directories with this exact name, as shown in the
// dashboard's identity provider settings.
Name string
}
DirectoryListOptions extends ListOptions with the filters every directory list endpoint accepts. Shared across the three providers, which expose the same filter surface.
type EmailOTPAuthProvider ¶
type EmailOTPAuthProvider struct {
AuthProvider
}
EmailOTPAuthProvider signs users in with a one-time passcode emailed to them. Unlike the other types it has no is_default flag - it is a fallback rather than something a sign-in page defaults to.
type EmailOTPAuthProvidersService ¶
type EmailOTPAuthProvidersService struct {
// contains filtered or unexported fields
}
EmailOTPAuthProvidersService reads Email OTP auth providers. Read-only - see AuthProvider.
func (*EmailOTPAuthProvidersService) Get ¶
func (s *EmailOTPAuthProvidersService) Get(ctx context.Context, id string) (*EmailOTPAuthProvider, error)
Get fetches a single Email OTP auth provider by ID.
func (*EmailOTPAuthProvidersService) List ¶
func (s *EmailOTPAuthProvidersService) List(ctx context.Context, opts *AuthProviderListOptions) (*Page[EmailOTPAuthProvider], error)
List returns a page of Email OTP auth providers. Pass nil for opts to use the API's default page size and no filters.
type EntraAuthProvider ¶
type EntraAuthProvider struct {
AuthProvider
IsDefault bool `json:"is_default"`
EmailClaim string `json:"email_claim"`
}
EntraAuthProvider is a Microsoft Entra sign-in provider.
type EntraAuthProvidersService ¶
type EntraAuthProvidersService struct {
// contains filtered or unexported fields
}
EntraAuthProvidersService reads Microsoft Entra auth providers. Read-only - see AuthProvider.
func (*EntraAuthProvidersService) Get ¶
func (s *EntraAuthProvidersService) Get(ctx context.Context, id string) (*EntraAuthProvider, error)
Get fetches a single Entra auth provider by ID.
func (*EntraAuthProvidersService) List ¶
func (s *EntraAuthProvidersService) List(ctx context.Context, opts *AuthProviderListOptions) (*Page[EntraAuthProvider], error)
List returns a page of Entra auth providers. Pass nil for opts to use the API's default page size and no filters.
type EntraDirectoriesService ¶
type EntraDirectoriesService struct {
// contains filtered or unexported fields
}
EntraDirectoriesService reads Entra directory connections. Read-only: there is no Create, Update, or Delete - see EntraDirectory.
func (*EntraDirectoriesService) Get ¶
func (s *EntraDirectoriesService) Get(ctx context.Context, id string) (*EntraDirectory, error)
Get fetches a single Entra directory by ID.
func (*EntraDirectoriesService) List ¶
func (s *EntraDirectoriesService) List(ctx context.Context, opts *DirectoryListOptions) (*Page[EntraDirectory], error)
List returns a page of Entra directories. Pass nil for opts to use the API's default page size and no filters.
type EntraDirectory ¶
type EntraDirectory struct {
ID string `json:"id"`
AccountID string `json:"account_id"`
Name string `json:"name"`
TenantID string `json:"tenant_id"`
IsDisabled bool `json:"is_disabled"`
DisabledReason string `json:"disabled_reason,omitempty"`
SyncedAt *time.Time `json:"synced_at,omitempty"`
ErrorMessage string `json:"error_message,omitempty"`
ErroredAt *time.Time `json:"errored_at,omitempty"`
EmailField string `json:"email_field"`
SyncAllGroups bool `json:"sync_all_groups"`
InsertedAt time.Time `json:"inserted_at"`
UpdatedAt time.Time `json:"updated_at"`
}
EntraDirectory is a Microsoft Entra directory connection. Directories are read-only via this API - they're managed through the Firezone dashboard's identity provider setup, not created or updated here.
type Filter ¶
type Filter struct {
Protocol FilterProtocol `json:"protocol"`
// Ports are port numbers or ranges (e.g. "80" or "8000 - 9000").
// Not applicable to FilterProtocolICMP.
Ports []string `json:"ports,omitempty"`
}
Filter restricts the protocols and ports a Resource exposes.
type FilterProtocol ¶
type FilterProtocol string
FilterProtocol is the transport protocol a Filter applies to.
const ( FilterProtocolTCP FilterProtocol = "tcp" FilterProtocolUDP FilterProtocol = "udp" FilterProtocolICMP FilterProtocol = "icmp" )
FilterProtocol values.
type Gateway ¶
type Gateway struct {
ID string `json:"id"`
Name string `json:"name"`
IPv4 string `json:"ipv4"`
IPv6 string `json:"ipv6"`
Online bool `json:"online"`
// GatewayTokenID is the token this Gateway last connected with.
// Empty until the Gateway connects for the first time.
GatewayTokenID string `json:"gateway_token_id,omitempty"`
// RotatedAt is when the token named by GatewayTokenID was rotated
// out, and is nil in the normal case. A non-nil value means a
// replacement token has been minted and this Gateway has not picked
// it up yet - see [Gateway.RotationPending].
RotatedAt *time.Time `json:"rotated_at,omitempty"`
}
Gateway is a Firezone Gateway - a host that exposes a Site's Resources to Clients.
IPv4 and IPv6 are the Gateway's tunnel addresses, allocated when the Gateway is created rather than on first connect, so both are always populated - including on a Gateway that has never connected. See LastSeenRemoteIP on the API's own responses for the public address.
func (*Gateway) RotationPending ¶
RotationPending reports whether a replacement token has been minted that this Gateway has not yet connected with.
While it is true the current token stays valid only until the Gateway connects with the replacement or the API's rotation grace period elapses from Gateway.RotatedAt, whichever comes first. A Gateway left in this state past the grace period is stranded: the API deletes the previous token once the replacement is confirmed, so rolling a host's configuration back to it will not work.
type GatewayListOptions ¶
type GatewayListOptions struct {
ListOptions
// Name filters to the Gateway with this exact name.
Name string
// IPv4 filters to the Gateway with this exact IPv4 address.
IPv4 string
// IPv6 filters to the Gateway with this exact IPv6 address.
IPv6 string
}
GatewayListOptions extends ListOptions with Gateways-specific filters. There's no SiteID filter here - the Site is already fixed by which GatewaysService you called List on (see SitesService.Gateways).
type GatewaysService ¶
type GatewaysService struct {
// contains filtered or unexported fields
}
GatewaysService manages the Gateways belonging to a single Site. Obtain one via SitesService.Gateways.
Token lifecycle ¶
A Gateway has at most one active token, and this service covers the whole of that token's life: GatewaysService.Provision creates the Gateway and mints its token together, GatewaysService.RotateToken replaces it, and GatewaysService.Delete destroys the Gateway and revokes it.
Two API endpoints are deliberately left out of that set:
- POST /sites/{site_id}/gateways/{gateway_id}/token creates a token for a Gateway that has none. Every Gateway this SDK creates goes through Provision, which already mints one, so calling it would always fail with 409 Conflict - the API allows only one active token per Gateway and directs callers to rotate instead. The endpoint is only useful for a Gateway created elsewhere, such as in the admin portal.
- POST /sites/{site_id}/gateway_tokens creates a multi-owner token shared by all of a Site's Gateways. The API marks it deprecated in favour of the per-Gateway endpoint above.
The DELETE counterparts under /sites/{site_id}/gateway_tokens are absent for the same reason: a token this SDK can create belongs to a Gateway, and deleting that Gateway revokes it. The one case this leaves uncovered is a Gateway stranded past a rotation grace period (see Gateway.RotationPending), which is recovered by deleting and re-provisioning the Gateway rather than by deleting its token.
If you need to adopt Gateways created outside this SDK, the token endpoints above are the gap to fill - adding them is additive, and IsConflict is already here for the 409 the first one returns.
func (*GatewaysService) Delete ¶
func (s *GatewaysService) Delete(ctx context.Context, id string) error
Delete deletes a Gateway, revoking its token. This is the only way this SDK revokes a token: see the GatewaysService doc comment for why the API's standalone token-deletion endpoints are not wrapped.
func (*GatewaysService) List ¶
func (s *GatewaysService) List(ctx context.Context, opts *GatewayListOptions) (*Page[Gateway], error)
List returns a page of the Site's Gateways. Pass nil for opts to use the API's default page size and no filters.
func (*GatewaysService) Provision ¶
func (s *GatewaysService) Provision(ctx context.Context, req *ProvisionGatewayRequest) (*ProvisionedGateway, error)
Provision creates a new Gateway and mints its single-owner token in one call. The returned Token is shown once - store it securely.
func (*GatewaysService) RotateToken ¶
func (s *GatewaysService) RotateToken(ctx context.Context, id string) (*RotatedGatewayToken, error)
RotateToken mints a replacement single-owner token for the Gateway, returning the new secret once.
The Gateway's current token is not invalidated immediately: it keeps working until the Gateway first connects with the replacement or the API's grace period elapses, whichever comes first. That window is the point - it exists so the replacement can be delivered to the Gateway host without downtime.
Two consequences worth planning for:
- Deliver the replacement and restart the Gateway before the grace period expires, or the Gateway is stranded. Poll Gateway.RotationPending to confirm pickup.
- Once pickup is confirmed the previous token is deleted, so rolling a host's configuration back to it will not work.
Rotating again before the Gateway picks up a pending replacement replaces only that pending token; the in-use one keeps its original deadline.
func (*GatewaysService) Update ¶
func (s *GatewaysService) Update(ctx context.Context, id string, req *UpdateGatewayRequest) (*Gateway, error)
Update renames a Gateway.
type GoogleAuthProvider ¶
type GoogleAuthProvider struct {
AuthProvider
IsDefault bool `json:"is_default"`
}
GoogleAuthProvider is a Google Workspace sign-in provider.
type GoogleAuthProvidersService ¶
type GoogleAuthProvidersService struct {
// contains filtered or unexported fields
}
GoogleAuthProvidersService reads Google Workspace auth providers. Read-only - see AuthProvider.
func (*GoogleAuthProvidersService) Get ¶
func (s *GoogleAuthProvidersService) Get(ctx context.Context, id string) (*GoogleAuthProvider, error)
Get fetches a single Google auth provider by ID.
func (*GoogleAuthProvidersService) List ¶
func (s *GoogleAuthProvidersService) List(ctx context.Context, opts *AuthProviderListOptions) (*Page[GoogleAuthProvider], error)
List returns a page of Google auth providers. Pass nil for opts to use the API's default page size and no filters.
type GoogleDirectoriesService ¶
type GoogleDirectoriesService struct {
// contains filtered or unexported fields
}
GoogleDirectoriesService reads Google Workspace directory connections. Read-only: there is no Create, Update, or Delete - see GoogleDirectory.
func (*GoogleDirectoriesService) Get ¶
func (s *GoogleDirectoriesService) Get(ctx context.Context, id string) (*GoogleDirectory, error)
Get fetches a single Google Workspace directory by ID.
func (*GoogleDirectoriesService) List ¶
func (s *GoogleDirectoriesService) List(ctx context.Context, opts *DirectoryListOptions) (*Page[GoogleDirectory], error)
List returns a page of Google Workspace directories. Pass nil for opts to use the API's default page size.
type GoogleDirectory ¶
type GoogleDirectory struct {
ID string `json:"id"`
AccountID string `json:"account_id"`
Name string `json:"name"`
Domain string `json:"domain"`
ImpersonationEmail string `json:"impersonation_email"`
IsDisabled bool `json:"is_disabled"`
DisabledReason string `json:"disabled_reason,omitempty"`
SyncedAt *time.Time `json:"synced_at,omitempty"`
ErrorMessage string `json:"error_message,omitempty"`
ErroredAt *time.Time `json:"errored_at,omitempty"`
GroupSyncMode string `json:"group_sync_mode"`
OrgUnitSyncEnabled bool `json:"orgunit_sync_enabled"`
InsertedAt time.Time `json:"inserted_at"`
UpdatedAt time.Time `json:"updated_at"`
}
GoogleDirectory is a Google Workspace directory connection. Directories are read-only via this API - they're managed through the Firezone dashboard's identity provider setup, not created or updated here.
type Group ¶
type Group struct {
ID string `json:"id"`
Name string `json:"name"`
Email string `json:"email,omitempty"`
EntityType string `json:"entity_type,omitempty"`
DirectoryID string `json:"directory_id,omitempty"`
IdpID string `json:"idp_id,omitempty"`
SyncedAt *time.Time `json:"synced_at,omitempty"`
InsertedAt time.Time `json:"inserted_at"`
UpdatedAt time.Time `json:"updated_at"`
}
Group is a Firezone actor Group. Groups synced from an identity provider have a non-empty DirectoryID and are read-only via this API (writes return 403 Forbidden) - see Group.IsSynced.
type GroupListOptions ¶
type GroupListOptions struct {
ListOptions
// Name filters to Groups with this exact name.
Name string
// DirectoryID filters to Groups synced from this directory. A
// pointer since the two meaningful "set" states aren't
// distinguishable through a plain string's zero value: nil means no
// filter, a pointer to "" filters to unsynced (native) Groups only,
// and a pointer to a directory ID filters to that directory. Use
// [String] to build the pointer inline, e.g. DirectoryID:
// firezone.String("").
DirectoryID *string
// EntityType filters to Groups of this entity type ("group" or
// "org_unit").
EntityType string
}
GroupListOptions extends ListOptions with Groups-specific filters.
type GroupMember ¶
type GroupMember struct {
ID string `json:"id"`
Name string `json:"name"`
Type ActorType `json:"type"`
}
GroupMember is an Actor's minimal representation as returned by MembershipsService.List.
type GroupsService ¶
type GroupsService struct {
// contains filtered or unexported fields
}
GroupsService manages Groups, and, nested under them, memberships.
func (*GroupsService) Create ¶
func (s *GroupsService) Create(ctx context.Context, req *CreateGroupRequest) (*Group, error)
Create creates a new (unsynced) Group.
func (*GroupsService) Delete ¶
func (s *GroupsService) Delete(ctx context.Context, id string) error
Delete deletes a Group. Returns 403 Forbidden if the Group is synced from an identity provider (see Group.IsSynced).
func (*GroupsService) List ¶
func (s *GroupsService) List(ctx context.Context, opts *GroupListOptions) (*Page[Group], error)
List returns a page of Groups. Pass nil for opts to use the API's default page size and no filters.
func (*GroupsService) Memberships ¶
func (s *GroupsService) Memberships(groupID string) *MembershipsService
Memberships returns a MembershipsService scoped to the Group identified by groupID.
func (*GroupsService) Update ¶
func (s *GroupsService) Update(ctx context.Context, id string, req *UpdateGroupRequest) (*Group, error)
Update updates a Group. Returns 403 Forbidden if the Group is synced from an identity provider (see Group.IsSynced).
type IPStack ¶
type IPStack string
IPStack constrains which IP families a Resource is reachable over.
type ListOptions ¶
type ListOptions struct {
// Limit is the maximum number of items to return. The API clamps
// this to the range [1, 100]; zero means "use the API default" (50).
Limit int
// PageCursor requests the page following (or preceding, when used
// with a PrevPage cursor) the one it was returned from. Leave empty
// to request the first page.
PageCursor string
}
ListOptions controls pagination for List methods. The zero value requests the API's default page (limit 50).
Example ¶
Paging is an explicit cursor loop: keep requesting until the metadata stops handing back a next-page cursor.
package main
import (
"context"
"fmt"
"log"
firezone "github.com/firezone/firezone-go"
)
func main() {
var client *firezone.Client // see [NewClient]
opts := &firezone.ResourceListOptions{
ListOptions: firezone.ListOptions{Limit: 100},
}
for {
page, err := client.Resources.List(context.Background(), opts)
if err != nil {
log.Fatal(err)
}
for _, resource := range page.Data {
fmt.Println(resource.Name)
}
if page.Metadata.NextPage == "" {
break
}
opts.PageCursor = page.Metadata.NextPage
}
}
Output:
type MembershipsService ¶
type MembershipsService struct {
// contains filtered or unexported fields
}
MembershipsService manages a single Group's memberships. Obtain one via GroupsService.Memberships.
func (*MembershipsService) List ¶
func (s *MembershipsService) List(ctx context.Context, opts *ListOptions) (*Page[GroupMember], error)
List returns a page of the Group's members.
func (*MembershipsService) Patch ¶
Patch adds and removes members from the Group without disturbing any other membership, returning the resulting member actor IDs. This is the safe choice when more than one caller manages membership on the same Group independently.
The operation is idempotent - adding an actor already in the Group and removing one that isn't are both no-ops - so a request that may already have been applied is safe to retry. Removals are applied before additions, so an ID passed in both add and remove ends up a member. Repeating an ID within either list is not an error; both are deduplicated. The returned IDs are sorted.
func (*MembershipsService) ReplaceAll ¶
ReplaceAll replaces the Group's entire membership list with actorIDs, returning the resulting member actor IDs. Unlike [Patch], this is a full replace: any actor not in actorIDs is removed.
Prefer [Patch] when multiple independent callers manage membership on the same Group - ReplaceAll from more than one caller will overwrite each other's changes.
Members that are not changing keep their server-side membership rows, so replacing a list with itself is a no-op rather than a full rewrite. Repeating an ID in actorIDs is not an error; the list is deduplicated. The returned IDs are sorted, not echoed back in the order they were sent.
type Null ¶
type Null[T any] struct { // Value is the value to send. Ignored unless Valid is true. Value T // Valid reports whether Value should be sent. When false, the field // is sent as JSON null. Valid bool }
Null holds an optional, nullable field in an update request.
The API's update endpoints are merge-patch: a field absent from the request body keeps its current value, while an explicit JSON null clears it. A plain Go string can't express both - its zero value is indistinguishable from "not set" - so nullable update fields are typed *Null[T], which has three states:
nil field omitted; the server keeps its current value Clear[T]() field sent as JSON null; the server clears it Set(v) field sent as v
Set("") also clears a nullable string field, rather than storing an empty one: the API's changeset treats "" as an empty value and replaces it with the field's default, which for a nullable field is null. Prefer Clear anyway - it says what it means, works for non-string types, and doesn't depend on that coincidence holding.
func Clear ¶
Clear returns a *Null that sends JSON null, clearing the field on the server. The type parameter is usually explicit, since there's no argument to infer it from: firezone.Clear[string]().
Example ¶
Clear removes a nullable field, which no plain string value can express: a nil pointer means "leave it alone", so there would otherwise be no way to say "set this to nothing".
package main
import (
"context"
"log"
firezone "github.com/firezone/firezone-go"
)
func main() {
var client *firezone.Client // see [NewClient]
_, err := client.Resources.Update(context.Background(), "resource-id",
&firezone.UpdateResourceRequest{
// Remove the description; leave every other field untouched.
AddressDescription: firezone.Clear[string](),
// Move the Resource to another Site.
SiteID: firezone.Set("site-id"),
})
if err != nil {
log.Fatal(err)
}
}
Output:
func (Null[T]) MarshalJSON ¶
MarshalJSON implements json.Marshaler, encoding an invalid Null as JSON null and a valid one as its value.
func (*Null[T]) UnmarshalJSON ¶
UnmarshalJSON implements json.Unmarshaler. A null decodes to the zero value with Valid false.
Note that encoding/json sets a *Null field to nil on JSON null without calling this method, so decoding cannot tell a cleared field from an omitted one. Null is an encode-side type; the SDK never decodes a request body, and read models use plain fields.
type OIDCAuthProvider ¶
type OIDCAuthProvider struct {
AuthProvider
IsDefault bool `json:"is_default"`
ClientID string `json:"client_id"`
DiscoveryDocumentURI string `json:"discovery_document_uri"`
EmailVerificationMethod string `json:"email_verification_method"`
}
OIDCAuthProvider is a generic OpenID Connect provider.
type OIDCAuthProvidersService ¶
type OIDCAuthProvidersService struct {
// contains filtered or unexported fields
}
OIDCAuthProvidersService reads generic OIDC auth providers. Read-only - see AuthProvider.
func (*OIDCAuthProvidersService) Get ¶
func (s *OIDCAuthProvidersService) Get(ctx context.Context, id string) (*OIDCAuthProvider, error)
Get fetches a single OIDC auth provider by ID.
func (*OIDCAuthProvidersService) List ¶
func (s *OIDCAuthProvidersService) List(ctx context.Context, opts *AuthProviderListOptions) (*Page[OIDCAuthProvider], error)
List returns a page of OIDC auth providers. Pass nil for opts to use the API's default page size and no filters.
type OktaAuthProvider ¶
type OktaAuthProvider struct {
AuthProvider
IsDefault bool `json:"is_default"`
ClientID string `json:"client_id"`
OktaDomain string `json:"okta_domain"`
}
OktaAuthProvider is an Okta sign-in provider.
type OktaAuthProvidersService ¶
type OktaAuthProvidersService struct {
// contains filtered or unexported fields
}
OktaAuthProvidersService reads Okta auth providers. Read-only - see AuthProvider.
func (*OktaAuthProvidersService) Get ¶
func (s *OktaAuthProvidersService) Get(ctx context.Context, id string) (*OktaAuthProvider, error)
Get fetches a single Okta auth provider by ID.
func (*OktaAuthProvidersService) List ¶
func (s *OktaAuthProvidersService) List(ctx context.Context, opts *AuthProviderListOptions) (*Page[OktaAuthProvider], error)
List returns a page of Okta auth providers. Pass nil for opts to use the API's default page size and no filters.
type OktaDirectoriesService ¶
type OktaDirectoriesService struct {
// contains filtered or unexported fields
}
OktaDirectoriesService reads Okta directory connections. Read-only: there is no Create, Update, or Delete - see OktaDirectory.
func (*OktaDirectoriesService) Get ¶
func (s *OktaDirectoriesService) Get(ctx context.Context, id string) (*OktaDirectory, error)
Get fetches a single Okta directory by ID.
func (*OktaDirectoriesService) List ¶
func (s *OktaDirectoriesService) List(ctx context.Context, opts *DirectoryListOptions) (*Page[OktaDirectory], error)
List returns a page of Okta directories. Pass nil for opts to use the API's default page size.
type OktaDirectory ¶
type OktaDirectory struct {
ID string `json:"id"`
AccountID string `json:"account_id"`
Name string `json:"name"`
ClientID string `json:"client_id"`
Kid string `json:"kid"`
OktaDomain string `json:"okta_domain"`
IsDisabled bool `json:"is_disabled"`
DisabledReason string `json:"disabled_reason,omitempty"`
SyncedAt *time.Time `json:"synced_at,omitempty"`
ErrorMessage string `json:"error_message,omitempty"`
ErroredAt *time.Time `json:"errored_at,omitempty"`
InsertedAt time.Time `json:"inserted_at"`
UpdatedAt time.Time `json:"updated_at"`
}
OktaDirectory is an Okta directory connection. Directories are read-only via this API - they're managed through the Firezone dashboard's identity provider setup, not created or updated here.
type Option ¶
Option configures a Client.
An Option returns an error rather than silently accepting bad input, so a misconfiguration is reported by NewClient at construction instead of surfacing later as a failed - or worse, a silently skipped - request. NewClient applies options in order and stops at the first error.
func WithHTTPClient ¶
WithHTTPClient sets the underlying *http.Client used for requests, replacing the default described in NewClient.
Supplying a client is how a caller sets its own timeout, transport, or proxy configuration. Passing nil is an error: it would otherwise panic with a nil dereference on the first request, pointing at the request rather than at the option that caused it.
func WithRequestTimeout ¶
WithRequestTimeout bounds a single HTTP attempt, from dialing to reading the response body. The default is defaultRequestTimeout.
This bounds one attempt, not a whole call: retry waits sit between requests rather than inside one, so a rate-limited call can still take longer overall, up to whatever budget WithRetry allows.
It is applied to the request context rather than to the underlying http.Client, so nothing here overrides anything else. A Timeout on a client passed to WithHTTPClient, a deadline already on the caller's context, and this option all apply together, and whichever expires first ends the attempt.
Zero means the SDK imposes no timeout of its own, leaving the deadline entirely to the caller's context and http.Client. A negative duration is an error - context.WithTimeout would treat it as an already-expired deadline, failing every request before it is sent.
func WithRetry ¶
WithRetry configures automatic retry-with-backoff on HTTP 429 (rate limited) responses. Retries are enabled by default with a budget of defaultMaxRetries.
Waits escalate exponentially, never drop below the response's Retry-After header, and always carry jitter so concurrent callers don't retry in lockstep.
maxRetries is the number of retries after the first attempt, so zero means "try once, do not retry". A negative budget is rejected rather than clamped: the retry loop runs maxRetries+1 times, so a negative value would make it run zero times and return no response and no error at all. Nothing a caller can mean by it is worth guessing at.
Example ¶
Retries are on by default and cover HTTP 429 only, honouring the API's Retry-After header. Tune the budget when a large concurrent run exhausts it.
package main
import (
"log"
"os"
firezone "github.com/firezone/firezone-go"
)
func main() {
client, err := firezone.NewClient("https://api.firezone.dev", os.Getenv("FIREZONE_TOKEN"),
firezone.WithRetry(true, 20),
)
if err != nil {
log.Fatal(err)
}
_ = client
}
Output:
func WithRetryMaxWait ¶
WithRetryMaxWait caps how long any single retry waits, bounding the exponential escalation. Zero or negative restores defaultMaxRetryWait.
Raise it when a large Terraform run is still exhausting its budget: a higher cap buys more total patience per retry than more attempts at a low cap does.
func WithUserAgent ¶
WithUserAgent replaces the User-Agent header sent with every request. It replaces rather than extends the default, so a caller that wants to keep the SDK's identity should include it:
firezone.WithUserAgent("terraform-provider-firezone/2.1.0 firezone-go-client/" + firezone.Version)
type Page ¶
type Page[T any] struct { Data []T Metadata PageMetadata }
Page is one page of results from a List method.
type PageMetadata ¶
type PageMetadata struct {
// Count is the total number of items across all pages.
Count int
// Limit is the page size that was actually applied.
Limit int
// NextPage is the cursor for the next page, or "" if this is the
// last page.
NextPage string
// PrevPage is the cursor for the previous page, or "" if this is
// the first page.
PrevPage string
}
PageMetadata describes a page of results returned by a List method.
type PoliciesService ¶
type PoliciesService struct {
// contains filtered or unexported fields
}
PoliciesService manages Policies.
func (*PoliciesService) Create ¶
func (s *PoliciesService) Create(ctx context.Context, req *CreatePolicyRequest) (*Policy, error)
Create creates a new Policy.
func (*PoliciesService) Delete ¶
func (s *PoliciesService) Delete(ctx context.Context, id string) error
Delete deletes a Policy.
func (*PoliciesService) Disable ¶
Disable disables a Policy, stopping it granting access without deleting it. Idempotent - disabling an already-disabled Policy is a no-op.
This is a convenience wrapper over PoliciesService.Update; the API has no dedicated disable endpoint.
func (*PoliciesService) Enable ¶
Enable enables a disabled Policy. Idempotent - enabling an already-enabled Policy is a no-op.
This is a convenience wrapper over PoliciesService.Update; the API has no dedicated enable endpoint.
func (*PoliciesService) List ¶
func (s *PoliciesService) List(ctx context.Context, opts *PolicyListOptions) (*Page[Policy], error)
List returns a page of Policies. Pass nil for opts to use the API's default page size and no filters.
func (*PoliciesService) Update ¶
func (s *PoliciesService) Update(ctx context.Context, id string, req *UpdatePolicyRequest) (*Policy, error)
Update updates a Policy.
type Policy ¶
type Policy struct {
ID string `json:"id"`
GroupID string `json:"group_id"`
ResourceID string `json:"resource_id"`
Description string `json:"description"`
FlowLogUploadsEnabled bool `json:"flow_log_uploads_enabled"`
IsDisabled bool `json:"is_disabled"`
Conditions []Condition `json:"conditions"`
}
Policy grants a Group access to a Resource, optionally restricted by Conditions.
type PolicyListOptions ¶
type PolicyListOptions struct {
ListOptions
// GroupID filters to Policies granting this Group.
GroupID string
// ResourceID filters to Policies granting access to this Resource.
ResourceID string
}
PolicyListOptions extends ListOptions with Policies-specific filters.
type PoolMember ¶
type PoolMember struct {
ID string `json:"id"`
Name string `json:"name"`
LastSeenAt *time.Time `json:"last_seen_at,omitempty"`
}
PoolMember is a Client's minimal representation as returned by PoolMembersService.List.
Pool members are Client devices, not Actors - a static device pool grants access to specific machines, so this is not the device-shaped equivalent of GroupMember despite the similar surface.
type PoolMembersService ¶
type PoolMembersService struct {
// contains filtered or unexported fields
}
PoolMembersService manages the membership of a single static_device_pool Resource. Obtain one via ResourcesService.PoolMembers.
Every method returns 400 if the Resource is not a static_device_pool; no other Resource type has members.
func (*PoolMembersService) List ¶
func (s *PoolMembersService) List(ctx context.Context, opts *ListOptions) (*Page[PoolMember], error)
List returns a page of the pool's member Clients.
func (*PoolMembersService) Patch ¶
Patch adds and removes Clients without disturbing any other member of the pool, returning the resulting member Client IDs. This is the safe choice when more than one caller manages membership on the same pool independently.
Both operations are idempotent: adding a Client already in the pool and removing one that isn't are both no-ops. remove is applied before add, so an ID in both slices ends up in the pool.
func (*PoolMembersService) ReplaceAll ¶
ReplaceAll replaces the pool's entire membership with deviceIDs, returning the resulting member Client IDs. Any Client not in deviceIDs is removed from the pool. Passing an empty slice clears it.
Prefer PoolMembersService.Patch when multiple independent callers manage membership on the same pool - ReplaceAll from more than one caller will overwrite each other's changes.
Returns 422 if any ID is not a Client in the account: a Gateway ID, a Client from another account, and a nonexistent ID all fail the same way.
type ProvisionGatewayRequest ¶
type ProvisionGatewayRequest struct {
Name string `json:"name,omitempty"`
}
ProvisionGatewayRequest is the request body for GatewaysService.Provision. Name is optional; the API generates a random name when omitted.
type ProvisionedGateway ¶
type ProvisionedGateway struct {
Gateway
// Token is the one-time Gateway token secret. Store it securely -
// it cannot be retrieved again.
Token string `json:"token"`
}
ProvisionedGateway is a newly provisioned Gateway along with its one-time token secret, returned only from GatewaysService.Provision. The API never re-exposes the token after creation - see GatewaysService.Get, which returns a plain Gateway with no token field at all, so the type system itself prevents a caller from expecting a token after a refresh.
type Resource ¶
type Resource struct {
ID string `json:"id"`
Name string `json:"name"`
Address string `json:"address"`
AddressDescription string `json:"address_description"`
Type ResourceType `json:"type"`
IPStack IPStack `json:"ip_stack,omitempty"`
SiteID string `json:"site_id,omitempty"`
Filters []Filter `json:"filters"`
}
Resource is a Firezone Resource - a network object (CIDR, IP, DNS name, or static device pool) that Policies grant access to.
type ResourceListOptions ¶
type ResourceListOptions struct {
ListOptions
// Name filters to Resources with this exact name.
Name string
// Type filters to Resources of this type.
Type ResourceType
// SiteID filters to Resources connected to this Site.
SiteID string
// Address filters to Resources with this exact address.
Address string
// IPStack filters to Resources with this exact ip_stack.
IPStack IPStack
}
ResourceListOptions extends ListOptions with Resources-specific filters.
type ResourceType ¶
type ResourceType string
ResourceType is the type of network object a Resource represents.
const ( ResourceTypeCIDR ResourceType = "cidr" ResourceTypeIP ResourceType = "ip" ResourceTypeDNS ResourceType = "dns" // ResourceTypeStaticDevicePool is currently readable but not // creatable: the API rejects any request that changes a Resource's // type to it, on both create and update, with a 422. Create device // pools in the admin portal instead. // // The constant stays because existing pools are still returned by // Get and List, still filterable via [ResourceListOptions.Type], and // still updatable and deletable - only the transition into this type // is refused. Note that restating an existing pool's own type on an // update is not a transition and is accepted. ResourceTypeStaticDevicePool ResourceType = "static_device_pool" )
Resource types. "internet" also exists but is API-read-only - the API returns 403 if you try to create or update one - so it's deliberately not offered as a constant here.
type ResourcesService ¶
type ResourcesService struct {
// contains filtered or unexported fields
}
ResourcesService manages Resources, and, nested under them, static device pool membership.
func (*ResourcesService) Create ¶
func (s *ResourcesService) Create(ctx context.Context, req *CreateResourceRequest) (*Resource, error)
Create creates a new Resource.
Two types cannot be created: "internet" (403 Forbidden) and ResourceTypeStaticDevicePool (422) - create device pools in the admin portal instead.
func (*ResourcesService) Delete ¶
func (s *ResourcesService) Delete(ctx context.Context, id string) error
Delete deletes a Resource.
func (*ResourcesService) List ¶
func (s *ResourcesService) List(ctx context.Context, opts *ResourceListOptions) (*Page[Resource], error)
List returns a page of Resources. Pass nil for opts to use the API's default page size and no filters.
func (*ResourcesService) PoolMembers ¶
func (s *ResourcesService) PoolMembers(resourceID string) *PoolMembersService
PoolMembers returns a PoolMembersService scoped to the static_device_pool Resource identified by resourceID. Calling it for any other Resource type is allowed, but every request that service makes will fail with 400.
func (*ResourcesService) Update ¶
func (s *ResourcesService) Update(ctx context.Context, id string, req *UpdateResourceRequest) (*Resource, error)
Update updates a Resource.
Changing a Resource's type to ResourceTypeStaticDevicePool is refused with a 422, the same as creating one. Restating an existing pool's own type is not a change and is accepted, so a caller that echoes the whole Resource back on update still works.
Example ¶
Update requests are merge-patch: a field left nil keeps its current value, so this renames a Resource without disturbing anything else.
package main
import (
"context"
"fmt"
"log"
firezone "github.com/firezone/firezone-go"
)
func main() {
var client *firezone.Client // see [NewClient]
updated, err := client.Resources.Update(context.Background(), "resource-id",
&firezone.UpdateResourceRequest{Name: "postgres-prod"})
if err != nil {
log.Fatal(err)
}
fmt.Println(updated.Name)
}
Output:
type RotatedGatewayToken ¶
type RotatedGatewayToken struct {
// ID is the new token's ID, which becomes the Gateway's
// GatewayTokenID once it connects with this token.
ID string `json:"id"`
// Token is the replacement secret. Store it securely - it cannot be
// retrieved again.
Token string `json:"token"`
}
RotatedGatewayToken is the replacement token minted by GatewaysService.RotateToken. Like ProvisionedGateway.Token, the secret is shown exactly once.
type SiteListOptions ¶
type SiteListOptions struct {
ListOptions
// Name filters to the Site with this exact name.
Name string
}
SiteListOptions extends ListOptions with Sites-specific filters.
type SitesService ¶
type SitesService struct {
// contains filtered or unexported fields
}
SitesService manages Sites, and, nested under them, Gateways.
func (*SitesService) Create ¶
func (s *SitesService) Create(ctx context.Context, req *CreateSiteRequest) (*Site, error)
Create creates a new Site.
func (*SitesService) Delete ¶
func (s *SitesService) Delete(ctx context.Context, id string) error
Delete deletes a Site.
func (*SitesService) Gateways ¶
func (s *SitesService) Gateways(siteID string) *GatewaysService
Gateways returns a GatewaysService scoped to the Site identified by siteID, matching the API's own URL nesting (/sites/{site_id}/gateways/...).
Example ¶
Gateways are nested under their Site, matching the API's own URLs. The token comes back exactly once, on provisioning.
package main
import (
"context"
"fmt"
"log"
firezone "github.com/firezone/firezone-go"
)
func main() {
var client *firezone.Client // see [NewClient]
gateway, err := client.Sites.Gateways("site-id").Provision(context.Background(),
&firezone.ProvisionGatewayRequest{Name: "gw-nyc-1"})
if err != nil {
log.Fatal(err)
}
// Store this now - the API never exposes it again.
fmt.Println(gateway.Token)
}
Output:
func (*SitesService) List ¶
func (s *SitesService) List(ctx context.Context, opts *SiteListOptions) (*Page[Site], error)
List returns a page of Sites. Pass nil for opts to use the API's default page size and no filters.
func (*SitesService) Update ¶
func (s *SitesService) Update(ctx context.Context, id string, req *UpdateSiteRequest) (*Site, error)
Update updates a Site.
type UpdateActorRequest ¶
type UpdateActorRequest struct {
Name string `json:"name,omitempty"`
Type ActorType `json:"type,omitempty"`
// Email is nullable, so it is typed [Null] - Clear[string]() removes
// the Actor's email, and a nil pointer leaves it alone.
Email *Null[string] `json:"email,omitempty"`
AllowEmailOTPSignIn *bool `json:"allow_email_otp_sign_in,omitempty"`
IsDisabled *bool `json:"is_disabled,omitempty"`
}
UpdateActorRequest is the request body for ActorsService.Update. Every field is optional; omitted fields keep their current value.
Changing Email to a different address signs the Actor out and unlinks their identity providers - see the API's actor update documentation for details.
Setting IsDisabled to true immediately revokes the Actor's active Client tokens and portal sessions. The API returns 403 Forbidden if it names the Actor behind the calling token - an Actor cannot disable itself.
type UpdateClientRequest ¶
type UpdateClientRequest struct {
Name string `json:"name"`
}
UpdateClientRequest is the request body for ClientsService.Update. Name is the only mutable field, and the API requires it, so it is always sent - omitting it on an empty value would produce a body the API rejects for a reason that doesn't name the field.
type UpdateGatewayRequest ¶
type UpdateGatewayRequest struct {
Name string `json:"name"`
}
UpdateGatewayRequest is the request body for GatewaysService.Update. Name is the only mutable field - a Gateway's Site is permanent.
type UpdateGroupRequest ¶
type UpdateGroupRequest struct {
Name string `json:"name,omitempty"`
}
UpdateGroupRequest is the request body for GroupsService.Update.
type UpdatePolicyRequest ¶
type UpdatePolicyRequest struct {
GroupID string `json:"group_id,omitempty"`
ResourceID string `json:"resource_id,omitempty"`
// Description is nullable, so it is typed [Null] - Clear[string]()
// removes it, and a nil pointer leaves it alone.
Description *Null[string] `json:"description,omitempty"`
FlowLogUploadsEnabled *bool `json:"flow_log_uploads_enabled,omitempty"`
IsDisabled *bool `json:"is_disabled,omitempty"`
// Conditions replaces the Policy's conditions wholesale. nil leaves
// them unchanged; a pointer to an empty slice removes all of them,
// making the Policy grant access unconditionally.
Conditions *[]Condition `json:"conditions,omitempty"`
}
UpdatePolicyRequest is the request body for PoliciesService.Update. Every field is optional; omitted fields keep their current value.
Setting IsDisabled to true stops the Policy granting access without deleting it.
Example (Conditions) ¶
The embedded lists are pointers for the same reason: a nil pointer leaves them alone, and a pointer to an empty slice removes them all.
package main
import (
"context"
"log"
firezone "github.com/firezone/firezone-go"
)
func main() {
var client *firezone.Client // see [NewClient]
// Restrict the Policy to two countries.
_, err := client.Policies.Update(context.Background(), "policy-id",
&firezone.UpdatePolicyRequest{
Conditions: &[]firezone.Condition{{
Property: firezone.ConditionPropertyRemoteIPLocationRegion,
Operator: firezone.ConditionOperatorIsIn,
Values: []string{"US", "CA"},
}},
})
if err != nil {
log.Fatal(err)
}
// Remove every condition, granting access unconditionally.
if _, err := client.Policies.Update(context.Background(), "policy-id",
&firezone.UpdatePolicyRequest{Conditions: &[]firezone.Condition{}}); err != nil {
log.Fatal(err)
}
}
Output:
type UpdateResourceRequest ¶
type UpdateResourceRequest struct {
Name string `json:"name,omitempty"`
Type ResourceType `json:"type,omitempty"`
Address *Null[string] `json:"address,omitempty"`
// AddressDescription is free-form text describing the address.
// Clear[string]() removes it. Set("") removes it too - the API
// replaces an empty string with the field's default rather than
// storing it - but Clear states the intent.
AddressDescription *Null[string] `json:"address_description,omitempty"`
IPStack *Null[IPStack] `json:"ip_stack,omitempty"`
// SiteID moves the Resource to another Site. Clearing it detaches
// the Resource from its Site, which the API only permits for device
// pool Resources.
SiteID *Null[string] `json:"site_id,omitempty"`
// Filters replaces the Resource's filters wholesale. nil leaves them
// unchanged; a pointer to an empty slice removes all of them.
Filters *[]Filter `json:"filters,omitempty"`
}
UpdateResourceRequest is the request body for ResourcesService.Update. All fields are optional; omitted fields keep their current value.
The nullable fields are typed Null so they can be cleared as well as set - see that type for the three states. Filters is a pointer to a slice for the same reason: a nil pointer leaves the Resource's filters alone, while a pointer to an empty slice removes all of them.
type UpdateSiteRequest ¶
type UpdateSiteRequest struct {
Name string `json:"name,omitempty"`
}
UpdateSiteRequest is the request body for SitesService.Update. All fields are optional; omitted fields keep their current value.