gatekeeper

package
v0.0.0-...-d0d2ad6 Latest Latest
Warning

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

Go to latest
Published: Apr 3, 2024 License: Apache-2.0, MIT Imports: 46 Imported by: 0

Documentation

Index

Constants

View Source
const (
	UserNamespaceType  = "user"
	GroupNamespaceType = "group"
)
View Source
const (
	IDTypeProject = "project"
	IDTypeGroup   = "organization"

	EndpointTypeETWrite = "et_write"
	EndpointTypeETRead  = "et_read"
	EndpointTypeTRWrite = "tr_write"
)
View Source
const (
	CacheClientKey = "gatekeeper/redisCache"
)

Variables

View Source
var ErrUnauthorized = errors.New("unauthorized")

Functions

func AuthMetrics

func AuthMetrics(registry prometheus.Registerer) gin.HandlerFunc

func AuthenticatedSessionRequired

func AuthenticatedSessionRequired(autoAuth bool, next gin.HandlerFunc) gin.HandlerFunc

Ensures request is authenticated. If autoAuth=true, will redirect client through the auth flow and then return back to this route. If autoAuth=false, will return an unauthorized response to client.

func Cache

func Cache(client redis.Cmdable, registry prometheus.Registerer) gin.HandlerFunc

Middleware to set the database clients on the context for downstream handlers.

func ClearAuthToken

func ClearAuthToken(ctx *gin.Context) error

Helper to clear the authToken in the session.

func Config

func Config(c *ConfigOptions) gin.HandlerFunc

Middleware to set the config options on the context for downstream handlers.

func ErrorLogger

func ErrorLogger() gin.HandlerFunc

ErrorLogger middleware to log errors created with gin context. e.g. c.Error(err) or c.AbortWithError(500, err).

func GetAuthConfig

func GetAuthConfig(ctx *gin.Context) *oauth2.Config

Helper to get the oauth2 client config from the context.

func GetAuthToken

func GetAuthToken(ctx *gin.Context) *oauth2.Token

Helper to get the authToken from the session.

func GetNamespace

func GetNamespace(ctx *gin.Context) string

Helper to get the target namespaceID from the ctx.

func GetTopLevelGroupID

func GetTopLevelGroupID(ctx *gin.Context) int

func GetTopLevelNamespaceFromGroup

func GetTopLevelNamespaceFromGroup(ginCtx *gin.Context, groupID int) int

func GetTopLevelNamespaceFromProject

func GetTopLevelNamespaceFromProject(ginCtx *gin.Context, projectID int) int

func GroupAuthHandlerFactory

func GroupAuthHandlerFactory() gin.HandlerFunc

GroupAuthHandlerFactory returns an auth handler that will handle several cases of authn/authz for Group/Namespace membership.

func HandleAuthFinish

func HandleAuthFinish(ctx *gin.Context)

HandleAuthFinish handles the callback from GitLab during oauth2.

If user already has an active session, this handler will update it with the new auth token (in the case where the user changed identity in the GitLab instance). @Id AuthFinish @Summary Finish the OAuth2 Flow setting session on success @Router /v1/auth/callback [get] @Produce html @Success 200 "Complete auth flow" @Param code query string true "Authorization code" @Param state query string true "State parameter" @Failure 400 "Required parameters missing or state parameter does not match flow start state" @Failure 401 "Invalid authorization code or failure to exchange for access token"

func HandleAuthStart

func HandleAuthStart(ctx *gin.Context)

HandleAuthStart Initiates the oauth2 authentication with GitLab. @Id AuthStart @Summary Start the OAuth2 Flow @Router /v1/auth/start [get] @Produce html @Success 200 "Valid auth token already exists in the session" @Success 302 "OAuth2 redirect to GitLab with auth coded URL"

func HandleError

func HandleError(ctx *gin.Context, err error)

Returns a 401 if the error is due to an authorization issue, or aborts with the error and a generic message back to the user.

func HandleGLAccessTokenAuth

func HandleGLAccessTokenAuth(ctx *gin.Context, bearerToken string, requiredScopes []string)

func HandleGroupAccessAuth

func HandleGroupAccessAuth(ginCtx *gin.Context, namespaceID, minAccessLevel int)

func HandleNamespaceProvisioning

func HandleNamespaceProvisioning(ctx *gin.Context)

Handles incoming requests for a Gitlab namespace for namespaces that do not yet exist in Opstrace. If the request lands here, we need to provision the namespace in Opstrace. This is a lazy provisioner that only provisions namespaces when the first request comes in for that namespace. Request must have Owner permissions on the respective GitLab namespace to proceed.

See the namespace API docs in gitlab https://docs.gitlab.com/ee/api/namespaces.html

@Id NamespaceProvisioning @Summary Handles provisioning of new namespaces. @Router /v1/provision/{namespace_id}/{action} [get] @Param namespace_id path string true "Namespace ID" @Param action path string false "Action URL part" @Success 302 "Redirect to provisioned UI" @Failure 401 "Unauthorized" @Failure 404 "Namespace not found" @Deprecated

func HandlePath

func HandlePath(ctx *gin.Context)

HandlePath catches any gitlab namespace and redirects to UI if already provisioned, or returns HTML with button to provision. @Id HandleNamespacePath @Summary Handles wildcard paths to namespace related components. @Router /-/{namespace_id}/{action} [get] @Param namespace_id path string true "Namespace ID" @Param action path string false "Action URL part" @Deprecated

func HandleProjectAccessAuth

func HandleProjectAccessAuth(
	ginCtx *gin.Context,
	projectID, minAccessLevelKey int,
)

Handles the token-based external auth request from ingress, both oauth-based session as well as Gitlab Access Token.

func HandleTokenAuth

func HandleTokenAuth(ctx *gin.Context)

Handles the token-based external auth request from ingress, both oauth-based session as well as Gitlab Access Token.

func ListGroupProjectsHandler

func ListGroupProjectsHandler(ctx *gin.Context)

ListGroupProjectsHandler lists all projects in a group. @Id ListGroupProjectsHandler @Summary Lists all projects in a group, used internally. @Router /v1/{group_id}/projects [get] @Param group_id path string true "Group ID" @Success 200 {array} Projects "GitLab projects" @Provides json @Deprecated

func OAuth2

func OAuth2(o *AuthOptions) gin.HandlerFunc

Make the oauth2 config available on the request context. Handlers can then invoke the the oauth flow and use the authenticated http.client for interacting with the gitlab API that is available on the oauth2.Config object.

func ProjectAuthHandlerFactory

func ProjectAuthHandlerFactory(namespacedPath bool) gin.HandlerFunc

ProjectAuthHandlerFactory returns an auth handler that will handle several cases of auth for project membership.

func RateLimitingHandler

func RateLimitingHandler() gin.HandlerFunc

handleRateLimiting checks if the request that belongs to given `limitID` group is permitted/below the quota limits for given topLevelGroupID. The return value signifies whether the request was rate limited or not, in case e.g. extra headers need to be added.

func ReadAccessTokenScopes

func ReadAccessTokenScopes() []string

ReadAccessTokenScopes returns scope sets. Token needs to have one or more of them in order for request to be granted.

func ReadWriteAccessTokenScopes

func ReadWriteAccessTokenScopes() []string

func Session

func Session(client redis.Cmdable, o *SessionOptions) []gin.HandlerFunc

Session middleware that stores session state in redis.

func SetAuthConfig

func SetAuthConfig(ctx *gin.Context, cfg *oauth2.Config)

Helper to set the oauth2 client config on the context.

func SetAuthToken

func SetAuthToken(ctx *gin.Context, token *oauth2.Token) error

Helper to set the authToken in the session.

func SetGitLabService

func SetGitLabService(ctx *gin.Context, us *GitLabService)

Helper to set the gitLabService on the context.

func SetRateLimiter

func SetRateLimiter(rl RateLimiter) gin.HandlerFunc

Middleware to set the ratelimiter in the Gin's context for downstream handlers..

func SetRoutes

func SetRoutes(router *gin.Engine, debugMode bool)

Sets up the gatekeeper routes.

func VerifyProjectGroupMembership

func VerifyProjectGroupMembership(
	ginCtx *gin.Context,
	namespaceID, projectID int,
)

func WriteAccessTokenScopes

func WriteAccessTokenScopes() []string

Types

type AuthMetricsData

type AuthMetricsData struct {
	LoginStarts    prometheus.Counter
	LoginSuccesses prometheus.Counter
	LoginFailures  prometheus.Counter
}

func GetAuthMetrics

func GetAuthMetrics(ctx *gin.Context) *AuthMetricsData

Helper to get the metrics from the context.

type AuthOptions

type AuthOptions struct {
	ClientID     string
	ClientSecret string
	GitlabAddr   string
	ServerDomain string
}

type CacheAdapter

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

func NewCacheAdapter

func NewCacheAdapter(size int, ttl time.Duration, evictionCallback func(bool)) *CacheAdapter

func (*CacheAdapter) Del

func (ca *CacheAdapter) Del(key string)

func (*CacheAdapter) Get

func (ca *CacheAdapter) Get(key string) ([]byte, bool)

func (*CacheAdapter) Set

func (ca *CacheAdapter) Set(key string, data []byte)

type CacheMetricsWrapper

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

func NewCacheMetricsWrapper

func NewCacheMetricsWrapper(registry prometheus.Registerer) *CacheMetricsWrapper

func (*CacheMetricsWrapper) EvictionCallback

func (cwm *CacheMetricsWrapper) EvictionCallback(isObjectAdd bool)

func (*CacheMetricsWrapper) Get

func (cwm *CacheMetricsWrapper) Get(
	ctx context.Context,
	key string,
	value interface{},
) error

func (*CacheMetricsWrapper) Set

func (cwm *CacheMetricsWrapper) Set(item *cache.Item) error

func (*CacheMetricsWrapper) SetCacheObject

func (cwm *CacheMetricsWrapper) SetCacheObject(c *cache.Cache)

type CacheOptions

type CacheOptions struct {
	RedisAddr          string
	RedisPassword      string
	ConnectionPoolSize int
	Registry           prometheus.Registerer
}

type ConfigOptions

type ConfigOptions struct {
	Port                        string
	UseSecureCookie             bool
	CookieName                  string
	CookieSecret                string
	OauthClientID               string
	OauthClientSecret           string
	ServerDomain                string
	GitlabAddr                  string
	GitlabInternalEndpointAddr  string
	GitlabInternalEndpointToken string
	K8sClient                   client.Client
	Namespace                   string
}

func GetConfig

func GetConfig(ctx *gin.Context) *ConfigOptions

Helper to get the server config from the context.

type CustomErrorsParams

type CustomErrorsParams struct {
	Code        int    `json:"code" form:"code" binding:"required,numeric,min=400,max=599"`
	OriginalURI string `json:"uri" form:"uri"  binding:"required"`
}

CustomErrorsParams defines the parameters for the custom errors handler

type EmptyValue

type EmptyValue struct{}

type ErrorTrackingAuthHandler

type ErrorTrackingAuthHandler interface {
	HandleErrorTrackingAuth(ctx *gin.Context)
}

func NewErrorTrackingAuthHandler

func NewErrorTrackingAuthHandler() ErrorTrackingAuthHandler

type GitLabGroup

type GitLabGroup struct {
	*gitlab.Group
}

func (*GitLabGroup) Equals

func (n *GitLabGroup) Equals(other *GitLabGroup) bool

GetTopLevel returns top-level parent namespace for this child namespace.

func (*GitLabGroup) GetTopLevelNamespaceID

func (n *GitLabGroup) GetTopLevelNamespaceID() string

GetTopLevel returns top-level parent namespace for this child namespace.

func (*GitLabGroup) IsTopLevel

func (n *GitLabGroup) IsTopLevel() bool

IsTopLevel returns true if this namespace is a top-level namespace. Returns false if this is a child namespace.

type GitLabNamespace

type GitLabNamespace struct {
	*gitlab.Namespace
}

func (*GitLabNamespace) Equals

func (n *GitLabNamespace) Equals(other *GitLabNamespace) bool

GetTopLevel returns top-level parent namespace for this child namespace.

func (*GitLabNamespace) GetTopLevelNamespaceID

func (n *GitLabNamespace) GetTopLevelNamespaceID() string

GetTopLevel returns top-level parent namespace for this child namespace.

func (*GitLabNamespace) IsTopLevel

func (n *GitLabNamespace) IsTopLevel() bool

IsTopLevel returns true if this namespace is a top-level namespace. Returns false if this is a child namespace.

type GitLabService

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

func GetGitLabService

func GetGitLabService(ctx *gin.Context) *GitLabService

Helper to get the gitLabService from the context.

func NewGitLabServiceFromAccessToken

func NewGitLabServiceFromAccessToken(requestCtx *gin.Context, bearerToken string) (*GitLabService, error)

Returns an instance of GitLabService that uses an http.Client configured with the access token. All GET requests against GitLab are cached.

func NewGitLabServiceFromOauthToken

func NewGitLabServiceFromOauthToken(ctx *gin.Context) (*GitLabService, error)

Returns an instance of GitLabService that uses an http.Client configured with the Oauth token taken from the request context. The http.Client will handle token.access_token expiry and request a new access_token using token.refresh_token. All GET requests against GitLab are cached.

func (*GitLabService) CanAccessNamespace

func (s *GitLabService) CanAccessNamespace(nid string) (bool, gitlab.AccessLevelValue, error)

Check if current user can access the namespace by Id.

func (*GitLabService) CanAccessProject

func (s *GitLabService) CanAccessProject(pid, minAccessLevelKey int) (bool, error)

Check if current user can access the namespace by Id.

func (*GitLabService) CurrentUser

func (s *GitLabService) CurrentUser() (*gitlab.User, error)

Get the current user.

func (*GitLabService) GetAccessTokenScopes

func (s *GitLabService) GetAccessTokenScopes() ([]string, error)

GetAccessTokenScopes returns the list of scopes assigned to the access token that this instance of GitlabService uses.

This method is added here because it doesn't exist in the underlying library

Docs: https://docs.gitlab.com/ee/api/personal_access_tokens.html#using-a-request-header

func (*GitLabService) GetGroup

func (s *GitLabService) GetGroup(gid string) (*GitLabGroup, error)

Get GitLab group by Id.

func (*GitLabService) GetGroupProjects

func (s *GitLabService) GetGroupProjects(gid interface{}) ([]*gitlab.BasicProject, error)

GetGroupProjects return all the projects available under passed Group ID.

func (*GitLabService) GetInheritedGroupMember

func (s *GitLabService) GetInheritedGroupMember(
	gid int, user int,
) (*gitlab.GroupMember, error)

GetGroupMember gets a member of a group, including inherited membership. This method is added here because it doesn't exist in the underlying library

GitLab API docs: https://docs.gitlab.com/ee/api/members.html#get-a-member-of-a-group-or-project-including-inherited-and-invited-members

func (*GitLabService) GetInheritedProjectMember

func (s *GitLabService) GetInheritedProjectMember(pid, user int) (*gitlab.ProjectMember, error)

func (*GitLabService) GetNamespace

func (s *GitLabService) GetNamespace(nid string) (*GitLabNamespace, error)

Get GitLab namespace by Id.

func (*GitLabService) GetProject

func (s *GitLabService) GetProject(pid interface{}) (*gitlab.Project, error)

Get Project

func (*GitLabService) GetTopLevelGroups

func (s *GitLabService) GetTopLevelGroups() ([]*GitLabGroup, error)

Get GitLab group by Id.

func (*GitLabService) HandleError

func (s *GitLabService) HandleError(err error) error

TODO: Investigate usage.

func (*GitLabService) IsProjectInGroup

func (s *GitLabService) IsProjectInGroup(pid, gid int) (bool, error)

IsProjectInGroup checks if given project belongs to the given namespace id.

func (*GitLabService) IsProjectInUserNamespace

func (s *GitLabService) IsProjectInUserNamespace(pid, nsid int) (bool, error)

IsProjectInGroup checks if given project is in the user-namespace. NOTE(prozlach) The way we do it is a bit hacky. According to the documentation:

https://docs.gitlab.com/ee/api/namespaces.html

``` A personal namespace, which is based on your username and provided to you when you create your account.

  • You cannot create subgroups in a personal namespace.
  • Groups in your namespace do not inherit your namespace permissions and group features.
  • All the projects you create are under the scope of this namespace.

```

The way I interpret it is that even if we have groups in the user NS (haven't found a way to create them), you will be only to create projects in the namespace itself, not it in the group. Creation of subgroups does not apply here either, nor the permissions inheritance, so no need to check hierarchy.

So the idea is simple - fetch the project and see the namespace it is sitting in. If it is the same as the one we are looking for - return true, return false otherwise.

func (*GitLabService) ListProjectsGroups

func (s *GitLabService) ListProjectsGroups(pid interface{}) ([]*gitlab.ProjectGroup, error)

Get Projects ancestor groups, sorted in descending order, top-level NS first

func (*GitLabService) Token

func (s *GitLabService) Token() (*oauth2.Token, error)

Returns latest issued token. A new token may have been issued through a refresh request and we need to store it. Returns nil if token is invalid (i.e. issued a refresh request and it failed).

type GroupAuthHandlerFormParams

type GroupAuthHandlerFormParams struct {
	MinAccessLevel *int  `json:"min_accesslevel" form:"min_accesslevel" binding:"required,numeric,min=0,max=50"`
	AutoAuth       *bool `json:"auto_auth" form:"auto_auth" binding:"required,boolean"`
}

type GroupAuthHandlerPathParams

type GroupAuthHandlerPathParams struct {
	NamespaceID int    `uri:"namespace_id" binding:"required,numeric,min=1"`
	Action      string `uri:"action" binding:"required,oneof=read write readwrite"`
}

type GroupParams

type GroupParams struct {
	ID string `uri:"group_id" binding:"required"`
}

type IngestAuthHeader

type IngestAuthHeader struct {
	SentryAuth string `header:"X-Sentry-Auth" binding:"required"`
}

func (IngestAuthHeader) ParseSentryKey

func (h IngestAuthHeader) ParseSentryKey() (string, error)

type LimitIDRateLimitHandlerFormParams

type LimitIDRateLimitHandlerFormParams struct {
	LimitID *string `json:"limit_id" form:"limit_id" binding:"omitempty,oneof=tr_write et_read et_write"`
}

type NamespaceParams

type NamespaceParams struct {
	ID     string `uri:"namespace_id" binding:"required"`
	Action string `uri:"action"`
}

type NamespacePathParam

type NamespacePathParam struct {
	NamespaceID int `uri:"namespace_id" binding:"required,numeric,min=1"`
}

type NamespaceWatcher

type NamespaceWatcher struct {
	// This client, initialized using mgr.Client() above, is a split client
	// that reads objects from the cache and writes to the apiserver
	Client    client.Client
	Scheme    *runtime.Scheme
	Transport *http.Transport
	Log       logr.Logger
	Namespace string
}

NamespaceWatcher reconciles a Cluster object.

func (*NamespaceWatcher) Reconcile

func (r *NamespaceWatcher) Reconcile(ctx context.Context, request reconcile.Request) (ctrl.Result, error)

Although this is a reconciler, it's being used as a cache/watcher to log update events on the GitLabNamespace. This is helpful to track the status in the same process as we start the change (creation, updating, deleting) GitLabNamespaces. We can optionally in the future at a channel to push the status back to the gatekeeper API thread so that status can be communicated to the user.

func (*NamespaceWatcher) SetupWithManager

func (r *NamespaceWatcher) SetupWithManager(mgr ctrl.Manager) error

SetupWithManager sets up the controller with the Manager.

type PathFormParams

type PathFormParams struct {
	// The shortest prefix is `/projects/{projectId}` which for single-digit
	// project ID gives us 11 chars. Add to it the `/errortracking/api/v1`
	// prefix and you get the minimal length of 32.
	Path string `json:"request_path" form:"request_path" binding:"required,uri,min=32"`
}

type ProjectAuthHandlerFormParams

type ProjectAuthHandlerFormParams struct {
	MinAccessLevel *int  `json:"min_accesslevel" form:"min_accesslevel" binding:"required,numeric,min=0,max=50"`
	AutoAuth       *bool `json:"auto_auth" form:"auto_auth" binding:"required,boolean"`
}

type ProjectAuthHandlerPathParams

type ProjectAuthHandlerPathParams struct {
	ProjectID int    `uri:"project_id" binding:"required,numeric,min=1"`
	Action    string `uri:"action" binding:"required,oneof=read write readwrite"`
}

type Projects

type Projects = []*gitlab.BasicProject

Projects alias returned from handler

type RateLimiter

type RateLimiter interface {
	IsAllowed(context.Context, int, string, uint64) (*redis_rate.Result, error)
	SetLimits(*ratelimiting.LimitsConfig)
}

func GetRateLimiter

func GetRateLimiter(ctx *gin.Context) RateLimiter

Helper to get the ratelimiter from the context.

func NewNullRateLimiter

func NewNullRateLimiter() RateLimiter

func NewRateLimiter

func NewRateLimiter(limiter RateLimiterBackend) RateLimiter

type RateLimiterBackend

type RateLimiterBackend interface {
	AllowN(context.Context, string, redis_rate.Limit, int) (*redis_rate.Result, error)
}

type RedisCache

type RedisCache interface {
	Set(item *cache.Item) error
	Get(ctx context.Context, key string, value interface{}) error
}

func GetCache

func GetCache(ctx *gin.Context) RedisCache

Helper to get the Redis client from the context.

type RoutingParams

type RoutingParams struct {
	ID     string `uri:"namespace_id" binding:"required"`
	Action string `uri:"action"`
}

type SessionOptions

type SessionOptions struct {
	CookieName      string
	CookieSecret    string
	UseSecureCookie bool
	Registry        prometheus.Registerer
}

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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