Documentation
¶
Overview ¶
TODO: This code is based on athenz/k8s-athenz-sia's implementation: TODO: https://github.com/AthenZ/k8s-athenz-sia/blob/main/pkg/util/cert-reloader.go TODO: Yet, the original code is tailored specifically to k8s-athenz-sia's logic TODO: So we could not copy the k8s-athenz-sia's cert-reloader code as is. TODO: It would be beneficial to develop a more general-purpose library for this functionality in the future. TODO: This way, both Garm and k8s-athenz-sia could utilize the same library.
Package service manages the main logic of Garm. It contains a token updater to periodically update the N-token for communicating with Athenz, and processing K8s webhook requests. The K8s webhook requests may requires authentication check by Athenz. However, base on the Garm configuration, some requests can be rejected directly.
Index ¶
- Constants
- Variables
- func NewTLSConfig(cfg config.TLS) (*tls.Config, error)
- func NewX509CertPool(path string) (*x509.CertPool, error)
- type AKSResolve
- func (r *AKSResolve) BuildDomainsFromNamespace(namespace string) []string
- func (r *AKSResolve) BuildServiceAccountPrefixFromNamespace(namespace string) []string
- func (r *AKSResolve) GetAdminDomain(namespace string) string
- func (r *AKSResolve) GetEmptyNamespace() string
- func (r *AKSResolve) GetNonResourceGroup() string
- func (r *AKSResolve) GetNonResourceNamespace() string
- func (r *AKSResolve) IsAdminAccess(verb, namespace, apiGroup, resource, name string) bool
- func (r *AKSResolve) IsAllowed(verb, namespace, apiGroup, resource, name string) bool
- func (r *AKSResolve) MapAPIGroup(group string) string
- func (r *AKSResolve) MapK8sResourceAthenzResource(k8sRes string) string
- func (r *AKSResolve) MapResourceName(name string) string
- func (r *AKSResolve) MapVerbAction(verb string) string
- func (r *AKSResolve) PrincipalFromUser(user string, groups []string) string
- func (r *AKSResolve) TrimResource(res string) string
- type Athenz
- type CertReloader
- type CertReloaderCfg
- type EKSResolve
- func (r *EKSResolve) BuildDomainsFromNamespace(namespace string) []string
- func (r *EKSResolve) BuildServiceAccountPrefixFromNamespace(namespace string) []string
- func (r *EKSResolve) GetAdminDomain(namespace string) string
- func (r *EKSResolve) GetEmptyNamespace() string
- func (r *EKSResolve) GetNonResourceGroup() string
- func (r *EKSResolve) GetNonResourceNamespace() string
- func (r *EKSResolve) IsAdminAccess(verb, namespace, apiGroup, resource, name string) bool
- func (r *EKSResolve) IsAllowed(verb, namespace, apiGroup, resource, name string) bool
- func (r *EKSResolve) MapAPIGroup(group string) string
- func (r *EKSResolve) MapK8sResourceAthenzResource(k8sRes string) string
- func (r *EKSResolve) MapResourceName(name string) string
- func (r *EKSResolve) MapVerbAction(verb string) string
- func (r *EKSResolve) PrincipalFromUser(user string, groups []string) string
- func (r *EKSResolve) TrimResource(res string) string
- type K8SResolve
- func (r *K8SResolve) BuildDomainsFromNamespace(namespace string) []string
- func (r *K8SResolve) BuildServiceAccountPrefixFromNamespace(namespace string) []string
- func (r *K8SResolve) GetAdminDomain(namespace string) string
- func (r *K8SResolve) GetEmptyNamespace() string
- func (r *K8SResolve) GetNonResourceGroup() string
- func (r *K8SResolve) GetNonResourceNamespace() string
- func (r *K8SResolve) IsAdminAccess(verb, namespace, apiGroup, resource, name string) bool
- func (r *K8SResolve) IsAllowed(verb, namespace, apiGroup, resource, name string) bool
- func (r *K8SResolve) MapAPIGroup(group string) string
- func (r *K8SResolve) MapK8sResourceAthenzResource(k8sRes string) string
- func (r *K8SResolve) MapResourceName(name string) string
- func (r *K8SResolve) MapVerbAction(verb string) string
- func (r *K8SResolve) PrincipalFromUser(user string, groups []string) string
- func (r *K8SResolve) TrimResource(res string) string
- type LogFn
- type Logger
- type Resolver
- type ResourceMapper
- type Server
- type TokenService
- type UserMapper
Constants ¶
const ( // ContentType represents a HTTP header name "Content-Type" ContentType = "Content-Type" // TextPlain represents a HTTP content type "text/plain" TextPlain = "text/plain" // CharsetUTF8 represents a UTF-8 charset for HTTP response "charset=UTF-8" CharsetUTF8 = "charset=UTF-8" )
Variables ¶
var ( // ErrContextClosed represents the error that the context is closed ErrContextClosed = errors.New("context Closed") )
var ( // ErrTokenNotFound represents the error that the token is not found ErrTokenNotFound = errors.New("Error:\ttoken not found") )
Functions ¶
func NewTLSConfig ¶
NewTLSConfig returns a *tls.Config struct or error. It reads TLS configuration and initializes *tls.Config struct. It initializes TLS configuration, for example the CA certificate and key to start TLS server. Server and CA Certificate, and private key will read from files from file paths defined in environment variables.
Types ¶
type AKSResolve ¶
type AKSResolve struct {
// contains filtered or unexported fields
}
AKSResolve implementation for Azure AKS platform.
func (*AKSResolve) BuildDomainsFromNamespace ¶
BuildDomainsFromNamespace returns domains by processing athenzDomains. if namespace != "", replace `/ = .`, then `.. => -`, then replace "_namespace_" in athenzDomains with namespace; else replace "._namespace_" in athenzDomains with namespace; trim ".", then "-", then ":"
func (*AKSResolve) BuildServiceAccountPrefixFromNamespace ¶
BuildServiceAccountPrefixFromNamespace returns domains by processing AthenzServiceAccountPrefix.
if namespace != "", replace `/ = .`, then `.. => -`, then replace "_namespace_" in AthenzServiceAccountPrefix with namespace; else replace "._namespace_" in AthenzServiceAccountPrefix with namespace; trim ".", then "-", then ":"
func (*AKSResolve) GetAdminDomain ¶
GetAdminDomain process cfg.AdminAthenzDomain by 1. replace `/ => .`, and then `.. => -` in namespace 2. replace "_namespace_" to replaced namespace in cfg.AdminAthenzDomain 3. trim ".", then trim "-", then trim ":"
func (*AKSResolve) GetEmptyNamespace ¶
func (r *AKSResolve) GetEmptyNamespace() string
GetEmptyNamespace returns cfg.EmptyNamespace
func (*AKSResolve) GetNonResourceGroup ¶
func (r *AKSResolve) GetNonResourceGroup() string
GetNonResourceGroup returns cfg.NonResourceAPIGroup
func (*AKSResolve) GetNonResourceNamespace ¶
func (r *AKSResolve) GetNonResourceNamespace() string
GetNonResourceNamespace returns cfg.NonResourceNamespace
func (*AKSResolve) IsAdminAccess ¶
IsAdminAccess returns true, if any admin access in config match
func (*AKSResolve) IsAllowed ¶
IsAllowed returns true, if inside whitelist or not in both list returns false, only if inside blacklist i.e. return (in whitelist || not in blacklist)
func (*AKSResolve) MapAPIGroup ¶
MapAPIGroup returns "" if cfg.APIGroupControlEnabled == false; else returns cfg.APIGroupMappings mapped value if found, else return original name;
func (*AKSResolve) MapK8sResourceAthenzResource ¶
MapK8sResourceAthenzResource returns mapped value in cfg.ResourceMappings, else returns the same value.
func (*AKSResolve) MapResourceName ¶
MapResourceName returns "" if cfg.ResourceNameControlEnabled == false; else returns cfg.ResourceNameMappings mapped value if found, else return original name;
func (*AKSResolve) MapVerbAction ¶
MapVerbAction returns mapped value in cfg.VerbMappings, else returns the same value.
func (*AKSResolve) PrincipalFromUser ¶
PrincipalFromUser maps K8s user to Athenz principal. 1. service account: if has ServiceAccountPrefixes, remove prefix, map to AthenzServiceAccountPrefix 1.1. if contains namespace, create domain by the namespace and AthenzServiceAccountPrefix 1.2. if no namespaces, create domain by EmptyNamespace and AthenzServiceAccountPrefix 2. athenz user: if has AthenzUserPrefix, OR not contains ".", map to AthenzUserPrefix 3. certificate: if not service account and athenz user, no mapping
func (*AKSResolve) TrimResource ¶
TrimResource processes res by 1. `/ => .` 2. `.. => -` 3. `-:, :-, .:, :. => :` 4. trim ".", then trim "-", then trim ":" example: TrimResource(fmt.Sprintf("%s:%s.%s.%s", "domain", "group", "resource", "name")) => "domain:group.resource.name" TrimResource(fmt.Sprintf("%s:%s.%s.%s", ".-:domain", "group", "resource", "name:-.")) => "domain:group.resource.name" TrimResource(fmt.Sprintf("%s:%s.%s.%s", "do/ma//in", "gr..oup", "re-source", "n-:a:-m.:e:.")) => "do.ma-in:gr-oup.re-source.n:a:m:e"
type Athenz ¶
type Athenz interface { // AthenzAuthorizer sends HTTP requests to Athenz server for authorization. AthenzAuthorizer(http.ResponseWriter, *http.Request) error // AthenzAuthenticator sends HTTP requests to Athenz server for authentication. AthenzAuthenticator(http.ResponseWriter, *http.Request) error }
Athenz interface is used to send HTTP requests to Athenz server.
type CertReloader ¶ added in v3.2.0
type CertReloader struct {
// contains filtered or unexported fields
}
CertReloader reloads the (key, cert) pair from the filesystem when the cert file is updated.
func NewCertReloader ¶ added in v3.2.0
func NewCertReloader(config CertReloaderCfg) (*CertReloader, error)
NewCertReloader returns a CertReloader that reloads the (key, cert) pair whenever the cert file changes on the filesystem.
func (*CertReloader) Close ¶ added in v3.2.0
func (w *CertReloader) Close() error
Close stops CertReloader (or stops refreshing).
func (*CertReloader) GetCertFromCache ¶ added in v3.2.0
func (w *CertReloader) GetCertFromCache() (*tls.Certificate, error)
GetCertFromCache returns the latest known certificate.
func (*CertReloader) GetTLSConfigFunc ¶ added in v3.2.0
func (w *CertReloader) GetTLSConfigFunc() func() (*tls.Config, error)
GetTLSConfigFunc returns a tls-config-returning-function that is used to get X.509 Certificate stored in memory to connect to Athenz server type IdentityAthenzX509 = func() (*tls.Config, error)
type CertReloaderCfg ¶ added in v3.2.0
type CertReloaderCfg struct { CertPath string // path to the X.509 certificate file i.e) /var/run/athenz/tls.crt KeyPath string // path to the X.509 certificate key i.e) /var/run/athenz/tls.key // path to the X.509 CA file i.e) /var/run/athenz/ca.crt // This is optional and can be empty // If empty, the reloader will not load the CA file. CaPath string // duration between consecutive reads of the certificate and key file i.e) 10s, 30m, 24h // This is not optional as the library is not aware how long the cert is valid for. PollInterval time.Duration }
CertReloaderCfg contains the config for cert reload.
type EKSResolve ¶
type EKSResolve struct {
// contains filtered or unexported fields
}
EKSResolve implementation for Amazon EKS platform.
func (*EKSResolve) BuildDomainsFromNamespace ¶
BuildDomainsFromNamespace returns domains by processing athenzDomains. if namespace != "", replace `/ = .`, then `.. => -`, then replace "_namespace_" in athenzDomains with namespace; else replace "._namespace_" in athenzDomains with namespace; trim ".", then "-", then ":"
func (*EKSResolve) BuildServiceAccountPrefixFromNamespace ¶
BuildServiceAccountPrefixFromNamespace returns domains by processing AthenzServiceAccountPrefix.
if namespace != "", replace `/ = .`, then `.. => -`, then replace "_namespace_" in AthenzServiceAccountPrefix with namespace; else replace "._namespace_" in AthenzServiceAccountPrefix with namespace; trim ".", then "-", then ":"
func (*EKSResolve) GetAdminDomain ¶
GetAdminDomain process cfg.AdminAthenzDomain by 1. replace `/ => .`, and then `.. => -` in namespace 2. replace "_namespace_" to replaced namespace in cfg.AdminAthenzDomain 3. trim ".", then trim "-", then trim ":"
func (*EKSResolve) GetEmptyNamespace ¶
func (r *EKSResolve) GetEmptyNamespace() string
GetEmptyNamespace returns cfg.EmptyNamespace
func (*EKSResolve) GetNonResourceGroup ¶
func (r *EKSResolve) GetNonResourceGroup() string
GetNonResourceGroup returns cfg.NonResourceAPIGroup
func (*EKSResolve) GetNonResourceNamespace ¶
func (r *EKSResolve) GetNonResourceNamespace() string
GetNonResourceNamespace returns cfg.NonResourceNamespace
func (*EKSResolve) IsAdminAccess ¶
IsAdminAccess returns true, if any admin access in config match
func (*EKSResolve) IsAllowed ¶
IsAllowed returns true, if inside whitelist or not in both list returns false, only if inside blacklist i.e. return (in whitelist || not in blacklist)
func (*EKSResolve) MapAPIGroup ¶
MapAPIGroup returns "" if cfg.APIGroupControlEnabled == false; else returns cfg.APIGroupMappings mapped value if found, else return original name;
func (*EKSResolve) MapK8sResourceAthenzResource ¶
MapK8sResourceAthenzResource returns mapped value in cfg.ResourceMappings, else returns the same value.
func (*EKSResolve) MapResourceName ¶
MapResourceName returns "" if cfg.ResourceNameControlEnabled == false; else returns cfg.ResourceNameMappings mapped value if found, else return original name;
func (*EKSResolve) MapVerbAction ¶
MapVerbAction returns mapped value in cfg.VerbMappings, else returns the same value.
func (*EKSResolve) PrincipalFromUser ¶
PrincipalFromUser maps K8s user to Athenz principal. 1. service account: if has ServiceAccountPrefixes, remove prefix, map to AthenzServiceAccountPrefix 1.1. if contains namespace, create domain by the namespace and AthenzServiceAccountPrefix 1.2. if no namespaces, create domain by EmptyNamespace and AthenzServiceAccountPrefix 2. athenz user: if has AthenzUserPrefix, OR not contains ".", map to AthenzUserPrefix 3. certificate: if not service account and athenz user, no mapping
func (*EKSResolve) TrimResource ¶
TrimResource processes res by 1. `/ => .` 2. `.. => -` 3. `-:, :-, .:, :. => :` 4. trim ".", then trim "-", then trim ":" example: TrimResource(fmt.Sprintf("%s:%s.%s.%s", "domain", "group", "resource", "name")) => "domain:group.resource.name" TrimResource(fmt.Sprintf("%s:%s.%s.%s", ".-:domain", "group", "resource", "name:-.")) => "domain:group.resource.name" TrimResource(fmt.Sprintf("%s:%s.%s.%s", "do/ma//in", "gr..oup", "re-source", "n-:a:-m.:e:.")) => "do.ma-in:gr-oup.re-source.n:a:m:e"
type K8SResolve ¶
type K8SResolve struct {
// contains filtered or unexported fields
}
K8SResolve implementation for K8S platform.
func (*K8SResolve) BuildDomainsFromNamespace ¶
BuildDomainsFromNamespace returns domains by processing athenzDomains. if namespace != "", replace `/ = .`, then `.. => -`, then replace "_namespace_" in athenzDomains with namespace; else replace "._namespace_" in athenzDomains with namespace; trim ".", then "-", then ":"
func (*K8SResolve) BuildServiceAccountPrefixFromNamespace ¶
BuildServiceAccountPrefixFromNamespace returns domains by processing AthenzServiceAccountPrefix.
if namespace != "", replace `/ = .`, then `.. => -`, then replace "_namespace_" in AthenzServiceAccountPrefix with namespace; else replace "._namespace_" in AthenzServiceAccountPrefix with namespace; trim ".", then "-", then ":"
func (*K8SResolve) GetAdminDomain ¶
GetAdminDomain process cfg.AdminAthenzDomain by 1. replace `/ => .`, and then `.. => -` in namespace 2. replace "_namespace_" to replaced namespace in cfg.AdminAthenzDomain 3. trim ".", then trim "-", then trim ":"
func (*K8SResolve) GetEmptyNamespace ¶
func (r *K8SResolve) GetEmptyNamespace() string
GetEmptyNamespace returns cfg.EmptyNamespace
func (*K8SResolve) GetNonResourceGroup ¶
func (r *K8SResolve) GetNonResourceGroup() string
GetNonResourceGroup returns cfg.NonResourceAPIGroup
func (*K8SResolve) GetNonResourceNamespace ¶
func (r *K8SResolve) GetNonResourceNamespace() string
GetNonResourceNamespace returns cfg.NonResourceNamespace
func (*K8SResolve) IsAdminAccess ¶
IsAdminAccess returns true, if any admin access in config match
func (*K8SResolve) IsAllowed ¶
IsAllowed returns true, if inside whitelist or not in both list returns false, only if inside blacklist i.e. return (in whitelist || not in blacklist)
func (*K8SResolve) MapAPIGroup ¶
MapAPIGroup returns "" if cfg.APIGroupControlEnabled == false; else returns cfg.APIGroupMappings mapped value if found, else return original name;
func (*K8SResolve) MapK8sResourceAthenzResource ¶
MapK8sResourceAthenzResource returns mapped value in cfg.ResourceMappings, else returns the same value.
func (*K8SResolve) MapResourceName ¶
MapResourceName returns "" if cfg.ResourceNameControlEnabled == false; else returns cfg.ResourceNameMappings mapped value if found, else return original name;
func (*K8SResolve) MapVerbAction ¶
MapVerbAction returns mapped value in cfg.VerbMappings, else returns the same value.
func (*K8SResolve) PrincipalFromUser ¶
PrincipalFromUser maps K8s user to Athenz principal. 1. service account: if has ServiceAccountPrefixes, remove prefix, map to AthenzServiceAccountPrefix 1.1. if contains namespace, create domain by the namespace and AthenzServiceAccountPrefix 1.2. if no namespaces, create domain by EmptyNamespace and AthenzServiceAccountPrefix 2. athenz user: if has AthenzUserPrefix, OR not contains ".", map to AthenzUserPrefix 3. certificate: if not service account and athenz user, no mapping
func (*K8SResolve) TrimResource ¶
TrimResource processes res by 1. `/ => .` 2. `.. => -` 3. `-:, :-, .:, :. => :` 4. trim ".", then trim "-", then trim ":" example: TrimResource(fmt.Sprintf("%s:%s.%s.%s", "domain", "group", "resource", "name")) => "domain:group.resource.name" TrimResource(fmt.Sprintf("%s:%s.%s.%s", ".-:domain", "group", "resource", "name:-.")) => "domain:group.resource.name" TrimResource(fmt.Sprintf("%s:%s.%s.%s", "do/ma//in", "gr..oup", "re-source", "n-:a:-m.:e:.")) => "do.ma-in:gr-oup.re-source.n:a:m:e"
type LogFn ¶ added in v3.2.0
type LogFn func(format string, args ...interface{})
LogFn allows customized logging.
type Logger ¶
type Logger interface { // GetProvider returns the LogProvider function that returns the actual logger instance. GetProvider() webhook.LogProvider // GetLogFlags returns the LogFlags for log filter inside the actual logger instance. GetLogFlags() webhook.LogFlags // Close closes the output resources used by the logger. Close() error }
Logger is an intermediate interface to create an actual logger.
type Resolver ¶
type Resolver interface { // MapVerbAction maps K8s verb to Athenz action. MapVerbAction(string) string // MapK8sResourceAthenzResource maps K8s resources to resources in Athenz resource. MapK8sResourceAthenzResource(string) string // BuildDomainsFromNamespace creates Athenz domains with namespace. BuildDomainsFromNamespace(string) []string // BuildServiceAccountPrefixFromNamespace creates Athenz domains for service account with namespace. BuildServiceAccountPrefixFromNamespace(string) []string // PrincipalFromUser creates principal name from user. PrincipalFromUser(user string, groups []string) string // GetAdminDomain creates Athenz admin domain with namespace. GetAdminDomain(string) string // MapAPIGroup maps K8s API group to API group in Athenz resource. MapAPIGroup(group string) string MapResourceName(name string) string // GetEmptyNamespace returns the mapped value for empty K8s namespace. GetEmptyNamespace() string // GetNonResourceGroup returns the mapped value for K8s non-resource API group. GetNonResourceGroup() string // GetNonResourceNamespace returns the mapped value for K8s non-resource namespace. GetNonResourceNamespace() string // TrimResource sterilizes resources to match Athenz resource naming convention. TrimResource(string) string // IsAllowed returns true if the K8s request should to Athenz, else returns false if directly reject. IsAllowed(verb, namespace, apiGroup, resource, name string) bool // IsAdminAccess returns true if the K8s request should use Athenz admin domain. IsAdminAccess(verb, namespace, apiGroup, resource, name string) bool }
Resolver is used to map K8s webhook requests to Athenz requests. (Athenz cannot use ":", hence, needs mapping.)
func NewResolver ¶
NewResolver returns a new resolver using cfg.TLD.Platform. The actual return type depends on cfg.TLD.Platform.Name. k8s => K8SResolve aks => AKSResolve eks => EKSResolve
type ResourceMapper ¶
type ResourceMapper interface { webhook.ResourceMapper }
ResourceMapper allows for mapping from an authorization request to Athenz principals. Wrapper of webhook.ResourceMapper.
func NewResourceMapper ¶
func NewResourceMapper(resolver Resolver) ResourceMapper
NewResourceMapper creates a new ResourceMapper for mapping K8s resources to Athenz principals.
type Server ¶
Server represents a Garm server behaviour.
func NewServer ¶
NewServer returns a Server interface, which includes Webhook server and health check server structs. The webhook server is a http.Server instance, which the port number is read from "config.Server.Port" , and make use of the given handler.
The health check server is a http.Server instance, which the port number is read from "config.Server.HealthzPort" , and its handler always return HTTP Status OK (200) response on HTTP GET request.
type TokenService ¶
type TokenService interface { StartTokenUpdater(context.Context) TokenService GetToken() (string, error) // contains filtered or unexported methods }
TokenService represents an interface for user to get the token, and automatically update the token.
func NewTokenService ¶
func NewTokenService(cfg config.Token) (TokenService, error)
NewTokenService returns a TokenService. It initializes information that required to generate the token (for example, RefreshDuration, Expiration, PrivateKey, etc).
type UserMapper ¶
type UserMapper interface { webhook.UserMapper }
UserMapper allows for mapping from Athenz principals to k8s objects.
func NewUserMapper ¶
func NewUserMapper(resolver Resolver) UserMapper
NewUserMapper returns a UserMapper instance with given Resolver.