iam

package module
v1.2.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 16, 2025 License: Apache-2.0 Imports: 32 Imported by: 0

README

IAM: A Simple Identity and Access Management Package for use on the Alis Build Platform.

This package provides a straightforward way to manage identity and access control in your Go applications running on the Alis Build Platform, inspired by the Google IAM Policy framework.

Features

  • Authentication and Authorization: Handles both identification (authn) and authorization (authz).
  • Flexible Access Control: Determine if a Principal (user or service account) can perform a specific Permission (e.g., Get, Update, List) on a designated Resource.
  • Resource-Oriented Design: Aligns with Resource-Driven Development (RDD) principles as outlined in RDD and API Improvement Proposals.

Getting Started

This package is currently under development. Stay tuned for installation instructions and usage examples.

Documentation

Overview

Package iam is a simple Authorization package based on the Google IAM (Identity and Access Management) Policy framework involves defining and managing access controls for resources.

This package does handles the identification / authn part of the IAM framework, as well as the Authorisation / Authz side of the framework. It authorises whether a particular **Principal** (user or service account) is able to perform a particular **Permission** (Get, Update, List, etc.) on a particular **Resource**. A resource is defined in the context of a Resource Driven development framework as defined at [RDD](https://google.com) inline with the [API Improvement Proposals](https://aip.dev)

Index

Constants

View Source
const (
	// One of the headers that cloudrun uses to send the JWT token of the authorized requester
	AuthHeader = "authorization"
	// One of the headers that cloudrun uses to send the JWT token of the authorized requester
	ServerlessAuthHeader = "x-serverless-authorization"
	// The header that this Alis Build package uses to forward the JWT token of the authorized requester
	AlisForwardingHeader = "x-alis-forwarded-authorization"
	// The header that Google Cloud ESPv2 proxy uses to forward the JWT token of the authorized requester
	ProxyForwardingHeader = "x-forwarded-authorization"
	// The header that Google Cloud IAP uses to forward the JWT token of the authorized requester
	IAPJWTAssertionHeader = "x-goog-iap-jwt-assertion"
)
View Source
const ForwardedHostHeader = "x-forwarded-host"

Variables

This section is empty.

Functions

This section is empty.

Types

type Authenticator

type Authenticator struct {
	// contains filtered or unexported fields
}

func NewAuthenticator

func NewAuthenticator() *Authenticator

Creates a new Authenticator instance that can be used to authenticate users via the alis-build managed iam service.

func (*Authenticator) ForwardAuthorizationHeader

func (h *Authenticator) ForwardAuthorizationHeader(ctx context.Context, allowMissingAuthHeader bool) (context.Context, error)

ForwardAuthorizationHeader forwards the Authorization header in the incoming ctx to the outgoing ctx. Use this at the very top of your unary and streaming interceptors in the context of a gRPC web server.

  • ctx: the context
  • allowMissingAuthHeader: whether to not return an error if the Authorization header is missing. Only set to true if you have checked for authentication when required in the http server layer and you have some methods that do not require authentication.

func (*Authenticator) HandleAuthRequest

func (h *Authenticator) HandleAuthRequest(resp http.ResponseWriter, req *http.Request)

Reverse proxies to the authHost for all requests that have "/auth" as the prefix. You must first check if the request is an auth request using IsAuthRequest.

func (*Authenticator) HandleNotFoundOrAccessDenied

func (h *Authenticator) HandleNotFoundOrAccessDenied(resp http.ResponseWriter, req *http.Request)

Reverse proxies to /auth/denied which shows a message in the line of "Not found or you don't have access".

func (*Authenticator) IsAuthRequest

func (h *Authenticator) IsAuthRequest(req *http.Request) bool

Returns whether the request has "/auth" as the prefix.

func (*Authenticator) IsAuthenticated

func (h *Authenticator) IsAuthenticated(resp http.ResponseWriter, req *http.Request) bool

Returns whether user is authenticated. First checks if there is a valid access token cookie and attaches it as an Authorization header. If above failed, it checks for a refresh_token cookie and tries to do a refresh on the fly by hitting /auth/refresh. Lastly, it checks directly for a Authorization header.

func (*Authenticator) RedirectToSignIn

func (h *Authenticator) RedirectToSignIn(resp http.ResponseWriter, req *http.Request, postAuthRedirectUri string)

Redirects to /auth/signin and sets the post_auth_redirect_uri cookie to the current request URI so that the user can be redirected back after signing in.

  • resp: the http.ResponseWriter
  • req: the http.Request
  • postAuthRedirectUri: where to go after signing in. Use req.RequestURI to redirect back to the current page.

type Authorizer

type Authorizer struct {

	// The Identity
	Identity *Identity

	// The rpc method
	// Format: /package.service/method
	Method string

	// A generic cache that group resolvers can use to store data used to resolve group membership.
	// There is no need to store final results in this cache, as these are automatically cached by the Authorizer.
	// An example use case is to store the result of a database query to avoid duplicate queries if a query could
	// resolve more than one group membership.
	Cache *sync.Map
	// contains filtered or unexported fields
}

Authorizer is responsible for the Authorization (i.e. Access) part of the IAM service and lives for the duration of a grpc method call. It is used to authorize the requester while providing access to the policy cache and the member cache to prevent redundant calls.

func (*Authorizer) AddIdentityPolicy

func (a *Authorizer) AddIdentityPolicy()

AddIdentityPolicy adds a policy from the underlying Identity to the list of policies against which access will be validated. If the policy is not present in the Identity's jwt and a usersClient is provided, it will fetch the policy asynchronously. Will do nothing if identity is deployment service account or auth is already claimed. Auth is claimed if another method on this server is calling the method where this authorizer lives.

func (*Authorizer) AddPolicy

func (a *Authorizer) AddPolicy(policy *iampb.Policy)

AddPolicy adds a policy to the list of policies against which any access will be validated. Do not add policies that should not be evaluated in downstream access checks. To add a policy that should only be evaluated for a specific access check, use the optional policies parameter in the HasAccess method. Will do nothing if identity is deployment service account or auth is already claimed. Auth is claimed if another method on this server is calling the method where this authorizer lives.

func (*Authorizer) AddPolicyFromClientRpc

func (a *Authorizer) AddPolicyFromClientRpc(resource string, clientGetIamPolicyMethod func(ctx context.Context, req *iampb.GetIamPolicyRequest, opts ...grpc.CallOption) (*iampb.Policy, error))

Asynchronously fetches a policy on another server using a Grpc Client's GetIamPolicy method. Adds the fetched policy to the list of policies against which access will be validated. Will do nothing if identity is deployment service account or auth is already claimed. Auth is claimed if another method on this server is calling the method where this authorizer lives.

func (*Authorizer) AddPolicyFromServerRpc

func (a *Authorizer) AddPolicyFromServerRpc(resource string, serverGetIamPolicyMethod func(ctx context.Context, req *iampb.GetIamPolicyRequest) (*iampb.Policy, error))

Asynchronously fetches a policy from a locally implemented service's GetIamPolicy method. Adds the fetched policy to the list of policies against which access will be validated. Will do nothing if identity is deployment service account or auth is already claimed. Auth is claimed if another method on this server is calling the method where this authorizer lives.

func (*Authorizer) AsyncAddPolicy

func (a *Authorizer) AsyncAddPolicy(resource string, fetchFunc func() *iampb.Policy)

This function should rarely be used directly. Rather use the AddIdentityPolicy, AddPolicyFromClientRpc, or AddPolicyFromServerRpc functions. Asynchronously fetches a policy using the provided fetch function and adds it to the list of policies against which access will be validated.

func (*Authorizer) AuthorizeRpc

func (a *Authorizer) AuthorizeRpc() error

AuthorizeRpc checks if the Identity has access to the current rpc method based on all the provided policies. This method returns an gRPC compliant error message and should be handled accordingly and is intented to be used by rpc methods.

func (*Authorizer) HasAccess

func (a *Authorizer) HasAccess(permission string, policies ...*iampb.Policy) bool

HasAccess checks if the requester has access to the current method based on all the underlying policies as well as the optionally provided policies

func (*Authorizer) HasRole

func (a *Authorizer) HasRole(policies []*iampb.Policy, role string) bool

Returns whether the requester has the specified role in the list of specified policies. Does not look in the Policies stored in the Authorizer, but rather the provided policies.

func (*Authorizer) IsGroupMember

func (a *Authorizer) IsGroupMember(group string) bool

Returns whether identity is a member of the specified iam group.

func (*Authorizer) Policies

func (a *Authorizer) Policies() []*iampb.Policy

Policies returns the list of policies against which any access will be validated.

type BatchAuthorizer

type BatchAuthorizer struct {

	// The Identity
	Identity *Identity

	// The rpc method
	// Format: /package.service/method
	Method string

	// A generic cache that group resolvers can use to store data used to resolve group membership.
	// There is no need to store final results in this cache, as these are automatically cached by the Authorizer.
	// An example use case is to store the result of a database query to avoid duplicate queries if a query could
	// resolve more than one group membership.
	Cache *sync.Map
	// contains filtered or unexported fields
}

func (*BatchAuthorizer) Authorizer

func (b *BatchAuthorizer) Authorizer(resource string) *Authorizer

func (*BatchAuthorizer) CachePolicy

func (b *BatchAuthorizer) CachePolicy(resource string, policy *iampb.Policy)

Adds a policy to the pool of cached policies. Authorizers created from this batch authorizer share this cache to avoid duplicate fetches. Not directly added to any authorizer's policies used to check access.

type IAM

type IAM struct {

	// the users client to use for fetching user policies in case they are not provided in the JWT token
	UsersClient openIam.UsersServiceClient

	// the users server to use for fetching user policies in case they are not provided in the JWT token
	UsersServer openIam.UsersServiceServer
	// contains filtered or unexported fields
}

A server authorizer is setup once per grpc server and contains static information about the roles, permissions and functions to resolve group memberships.

func New

func New(opts ...IamOption) (*IAM, error)

New creates a new IAM object. ALIS_OS_PROJECT environment variable must be set. ALIS_PRODUCT_CONFIG environment variable must be set if the product_config parameter is not set in Parameter Manager(https://console.cloud.google.com/security/parametermanager/locations/global/parameters/product_config).

func (*IAM) Disable

func (i *IAM) Disable()

Disable removes any authentication checks across all Authorizers. Use this method for testing methods without enforcing authorization.

func (*IAM) NewAuthorizer

func (i *IAM) NewAuthorizer(ctx context.Context) (*Authorizer, context.Context, error)

NewAuthorizer creates a new authorizer which will live for the duration of the grpc method call.

It initializes an Authorizer with the provided IAM instance and performs the following actions:

  • Identity Extraction: Extracts the Identity from the context, which includes information about the caller's authentication status and associated policies.
  • Policy Initialization: If the extracted Identity has an associated policy, it is added to the Authorizer's list of policies.
  • Super Admin Handling: Checks if the Identity represents a super admin. If so, authorization checks are skipped.
  • Authorization Claiming: Marks the authorization as 'claimed' in the context to prevent redundant authorization checks within the same call. If the authorization is already claimed, it skips further checks.
  • Method Extraction: Extracts the gRPC method name from the context, which is crucial for determining the required permissions. If the method cannot be extracted and the caller is not a super admin, it returns an error.

The resulting Authorizer is then returned, ready to be used for access control decisions.

Parameters:

ctx: The context containing information about the gRPC call, including the Identity and the method being invoked.

Returns:

  • *Authorizer: A new Authorizer instance populated with the extracted Identity, method, and policies.
  • error: An error if any of the extraction or initialization steps fail.

func (*IAM) NewBatchAuthorizer

func (i *IAM) NewBatchAuthorizer(ctx context.Context) (*BatchAuthorizer, context.Context, error)

func (*IAM) RoleHasPermission

func (s *IAM) RoleHasPermission(role string, permission string) bool

RoleHasPermission check whether the specified role has the requested permission Arguments:

  • role: the Role resource name, for example 'roles/admin', 'roles/report.viewer', etc.
  • permission: the Permission, for example '/alis.in.reports.v1.ReportsService/GetReport'

func (*IAM) WithMemberResolver

func (s *IAM) WithMemberResolver(groupTypes []string, resolver func(ctx context.Context, groupType string, groupId string, principal *Authorizer) bool) *IAM

WithMemberResolver registers a function to resolve whether a requester is a member of a group. There can be multiple different types of groups, e.g. "team:engineering" (groupType = "team",groupId="engineering") A group always has a type, but does not always have an id, e.g. "team:engineering" (groupType = "team",groupId="engineering") vs "all" (groupType = "all",groupId=""). "user" and "serviceAccounts" are not allowed as group types. "domain" is a builtin group type that is resolved by checking if the requester's email ends with the group id. Results are cached per Authorizer.

type IamOption

type IamOption func(*IamOptions)

IamOption is a functional option for the New method.

func WithAdditionalSuperAdmins

func WithAdditionalSuperAdmins(superAdmins ...string) IamOption

Sets the additional super admins. By default, only the deployment service account is a super admin. Arguments:

  • superAdmins: the additional super admins e.g. 'user:<userId>', 'serviceAccount:<email>'

func WithUserServer

func WithUserServer(userServer openIam.UsersServiceServer) IamOption

Should only be used by the alis managed users service. WithUserServer sets the user server to use for fetching user policies in case they are not provided in the JWT token. If set, the default users client is not used.

func WithoutDefaultUsersClient

func WithoutDefaultUsersClient() IamOption

WithoutDefaultUsersClient disables the default users client which is normally called at "iam-users-{hash}.run.app:443" to fetch user policies in case they are not provided in the JWT token.

type IamOptions

type IamOptions struct {
	WithoutDefaultUsersClient bool
	UserServer                openIam.UsersServiceServer
	SuperAdmins               []string
}

IamOptions are the options for creating a new IAM object.

type Identity

type Identity struct {
	// contains filtered or unexported fields
}

Identity represents details on the entiry making the particular rpc request.

func ExtractIdentityFromCtx

func ExtractIdentityFromCtx(ctx context.Context, deploymentServiceAccountEmail string, superAdmins map[string]bool) (*Identity, error)

ExtractIdentityFromCtx returns the Identity making the request or for whom the request is being forwarded by a super admin.

func (*Identity) Accounts

func (r *Identity) Accounts() map[string]*jwt.Account

Returns the accounts that the caller is part of

func (*Identity) Email

func (r *Identity) Email() string

func (*Identity) GroupIds

func (r *Identity) GroupIds() []string

Returns the group Ids that the caller is part of Format: [{groupId}, ...]

func (*Identity) GroupNames

func (r *Identity) GroupNames() []string

Returns the groups that the caller is part of Format: [groups/{groupId}, ...]

func (*Identity) Id

func (r *Identity) Id() string

func (*Identity) IsDeploymentServiceAccount

func (r *Identity) IsDeploymentServiceAccount() bool

func (*Identity) IsGoogleIdentity

func (r *Identity) IsGoogleIdentity() bool

Returns whether the requester used a google identity to authenticate.

func (*Identity) IsServiceAccount

func (r *Identity) IsServiceAccount() bool

Returns whether the requester is a service account.

func (*Identity) Jwt

func (r *Identity) Jwt() string

func (*Identity) Policy

func (r *Identity) Policy() *iampb.Policy

func (*Identity) PolicyMember

func (r *Identity) PolicyMember() string

Returns the policy member string of the requester. E.g. user:123456789 or serviceAccount:alis-build@...

func (*Identity) UserName

func (r *Identity) UserName() string

Returns the user name of the requester. Format: users/{userId}

Directories

Path Synopsis
internal
jwt

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL