Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Authorization refactor in preparation for fine-grained authorization #12313

Merged
merged 55 commits into from
Oct 25, 2023
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
5017205
lxd/auth: Adds entitlement, object, and permission types and constants.
markylaing Sep 25, 2023
3ea15d2
lxd/auth: Adds functions for creating auth objects.
markylaing Sep 25, 2023
a52e978
lxd/auth: Adds tests for authorization objects.
markylaing Oct 9, 2023
1ec0160
lxd/auth: Extends the authorizer interface.
markylaing Sep 25, 2023
cfa3b77
lxd/auth: Update common authorizer for Authorizer interface extension.
markylaing Sep 25, 2023
9123f14
lxd/auth: Implement Authorizer for TLS driver.
markylaing Sep 25, 2023
822af45
lxd/auth: Implement Authorizer for RBAC driver.
markylaing Sep 25, 2023
a39a702
lxd: Do not set user access data in request context.
markylaing Sep 25, 2023
c2c5840
lxd: Update calls to auth package.
markylaing Sep 25, 2023
dbad9e2
lxd: Only allow missing access handler when AllowUntrusted is true.
markylaing Sep 25, 2023
7b250a6
lxd: Update allowPermission function.
markylaing Sep 25, 2023
fd9d911
lxd: Updates allowAuthenticated function.
markylaing Oct 19, 2023
d428bc7
lxd/db/operationtype: Updates Permission method.
markylaing Sep 25, 2023
67d9725
lxd/operations: Updates operation permissions.
markylaing Sep 25, 2023
154c204
lxd/db/cluster: Renames constants.go file.
markylaing Sep 27, 2023
1fb2633
lxd/db/cluster: Add storage bucket entity type.
markylaing Sep 27, 2023
7362589
lxd/db/cluster: Adds URLToEntityType function.
markylaing Sep 27, 2023
1e22bcb
lxd/db/cluster: Adds a unit test for the URLToEntityType function.
markylaing Sep 27, 2023
3abd114
lxd/project: Updates permission handling for projects.
markylaing Sep 25, 2023
8975800
lxd/project: Updates permissions tests.
markylaing Oct 20, 2023
f0b0dcc
lxd/events: Pass an auth.PermissionChecker into the event listener.
markylaing Sep 25, 2023
fbd635b
lxd-agent: Update call to AddListener for the LXD Agent.
markylaing Sep 25, 2023
74aa566
lxd: Update authorization for the /1.0 endpoint.
markylaing Sep 25, 2023
2db6fe5
lxd: Update authorization for cluster endpoints.
markylaing Sep 25, 2023
aa061f8
lxd: Update authorization for internal endpoints.
markylaing Sep 25, 2023
9306e35
lxd/metrics: Adds method to filter metrics with a permission checker.
markylaing Sep 25, 2023
ae092f4
lxd: Update authorization for metrics.
markylaing Sep 25, 2023
4cb57a1
lxd: Update authorization for projects API.
markylaing Sep 25, 2023
535c040
lxd: Updates authorization for certificates API.
markylaing Sep 25, 2023
f1bb54a
lxd: Updates authorization for events API.
markylaing Sep 25, 2023
0cc2aa3
lxd: Updates authorization for image API.
markylaing Sep 25, 2023
73a9ce3
lxd: Add/remove images and image aliases from authorizer.
markylaing Sep 25, 2023
46698f1
lxd: Update authorization for instances.
markylaing Sep 25, 2023
146f36c
lxd/instance/drivers: Add/remove/rename instances in authorizer.
markylaing Sep 25, 2023
cacb832
lxd: Update authorization for network ACL API.
markylaing Sep 25, 2023
8b494ab
lxd: Update network ACLs in the authorizer.
markylaing Sep 25, 2023
721e31a
lxd: Update authorization for network allocations.
markylaing Sep 25, 2023
444692e
lxd: Update authorization for network forwards.
markylaing Sep 25, 2023
c2ef675
lxd: Update authorization for network load balancers.
markylaing Sep 25, 2023
3147031
lxd: Update authorization for network peers.
markylaing Sep 25, 2023
92408de
lxd: Update authorization for network zones.
markylaing Sep 25, 2023
cb5919f
lxd: Update network zones in the authorizer.
markylaing Sep 25, 2023
ca20445
lxd: Update authorization for the networks API.
markylaing Sep 25, 2023
31df5be
lxd: Update networks in the authorizer.
markylaing Sep 25, 2023
8ee727e
lxd: Update authorization for operations.
markylaing Sep 25, 2023
d9322ff
lxd: Update authorization for profiles.
markylaing Sep 25, 2023
6000337
lxd: Update profiles in authorizer.
markylaing Sep 25, 2023
cac36ee
lxd: Update authorization for resources.
markylaing Sep 25, 2023
2d3a73c
lxd: Update authorization for storage buckets.
markylaing Sep 25, 2023
0c43e90
lxd: Update storage buckets in authorizer.
markylaing Sep 25, 2023
27d6fe4
lxd: Update authorization for storage pools.
markylaing Sep 25, 2023
2ff65b0
lxd: Update storage pools in authorizer.
markylaing Sep 25, 2023
cb9da5d
lxd: Update authorization for storage volumes.
markylaing Sep 25, 2023
3371cf9
lxd/storage: Add/Remove/Rename storage volumes in authorizer.
markylaing Sep 25, 2023
7c9f699
lxd: Update authorization for warnings.
markylaing Sep 25, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 99 additions & 21 deletions lxd/auth/authorization.go
Original file line number Diff line number Diff line change
@@ -1,62 +1,140 @@
package auth

import (
"context"
"fmt"
"net/http"

"github.com/canonical/lxd/lxd/certificate"
"github.com/canonical/lxd/shared/logger"
)

const (
// DriverTLS is the default TLS authorization driver. It is not compatible with OIDC or Candid authentication.
DriverTLS string = "tls"

// DriverRBAC is role-based authorization. It is not compatible with TLS authentication.
DriverRBAC string = "rbac"
)

// ErrUnknownDriver is the "Unknown driver" error.
var ErrUnknownDriver = fmt.Errorf("Unknown driver")

var authorizers = map[string]func() authorizer{
"tls": func() authorizer { return &tls{} },
"rbac": func() authorizer {
DriverTLS: func() authorizer { return &tls{} },
DriverRBAC: func() authorizer {
return &rbac{
resources: map[string]string{},
permissions: map[string]map[string][]string{},
permissions: map[string]map[string][]Permission{},
}
},
}

type authorizer interface {
Authorizer

init(name string, config map[string]any, logger logger.Logger, projectsGetFunc func() (map[int64]string, error))
load() error
init(driverName string, logger logger.Logger) error
load(ctx context.Context, certificateCache *certificate.Cache, opts Opts) error
}

// PermissionChecker is a type alias for a function that returns whether a user has required permissions on an object.
// It is returned by Authorizer.GetPermissionChecker.
type PermissionChecker func(object Object) bool

// Authorizer is the primary external API for this package.
type Authorizer interface {
AddProject(projectID int64, name string) error
DeleteProject(projectID int64) error
RenameProject(projectID int64, newName string) error
Driver() string
StopService(ctx context.Context) error

CheckPermission(ctx context.Context, r *http.Request, object Object, entitlement Entitlement) error
GetPermissionChecker(ctx context.Context, r *http.Request, entitlement Entitlement, objectType ObjectType) (PermissionChecker, error)

AddProject(ctx context.Context, projectID int64, projectName string) error
DeleteProject(ctx context.Context, projectID int64, projectName string) error
RenameProject(ctx context.Context, projectID int64, oldName string, newName string) error

AddCertificate(ctx context.Context, fingerprint string) error
DeleteCertificate(ctx context.Context, fingerprint string) error

AddStoragePool(ctx context.Context, storagePoolName string) error
DeleteStoragePool(ctx context.Context, storagePoolName string) error

AddImage(ctx context.Context, projectName string, fingerprint string) error
DeleteImage(ctx context.Context, projectName string, fingerprint string) error

AddImageAlias(ctx context.Context, projectName string, imageAliasName string) error
DeleteImageAlias(ctx context.Context, projectName string, imageAliasName string) error
RenameImageAlias(ctx context.Context, projectName string, oldAliasName string, newAliasName string) error

AddInstance(ctx context.Context, projectName string, instanceName string) error
DeleteInstance(ctx context.Context, projectName string, instanceName string) error
RenameInstance(ctx context.Context, projectName string, oldInstanceName string, newInstanceName string) error

AddNetwork(ctx context.Context, projectName string, networkName string) error
DeleteNetwork(ctx context.Context, projectName string, networkName string) error
RenameNetwork(ctx context.Context, projectName string, oldNetworkName string, newNetworkName string) error

AddNetworkZone(ctx context.Context, projectName string, networkZoneName string) error
DeleteNetworkZone(ctx context.Context, projectName string, networkZoneName string) error

StopStatusCheck()
AddNetworkACL(ctx context.Context, projectName string, networkACLName string) error
DeleteNetworkACL(ctx context.Context, projectName string, networkACLName string) error
RenameNetworkACL(ctx context.Context, projectName string, oldNetworkACLName string, newNetworkACLName string) error

UserAccess(username string) (*UserAccess, error)
UserIsAdmin(r *http.Request) bool
UserHasPermission(r *http.Request, projectName string, permission string) bool
AddProfile(ctx context.Context, projectName string, profileName string) error
DeleteProfile(ctx context.Context, projectName string, profileName string) error
RenameProfile(ctx context.Context, projectName string, oldProfileName string, newProfileName string) error

AddStoragePoolVolume(ctx context.Context, projectName string, storagePoolName string, storageVolumeType string, storageVolumeName string) error
DeleteStoragePoolVolume(ctx context.Context, projectName string, storagePoolName string, storageVolumeType string, storageVolumeName string) error
RenameStoragePoolVolume(ctx context.Context, projectName string, storagePoolName string, storageVolumeType string, oldStorageVolumeName string, newStorageVolumeName string) error

AddStorageBucket(ctx context.Context, projectName string, storagePoolName string, storageBucketName string) error
DeleteStorageBucket(ctx context.Context, projectName string, storagePoolName string, storageBucketName string) error
}

// Opts is used as part of the LoadAuthorizer function so that only the relevant configuration fields are passed into a
// particular driver.
type Opts struct {
config map[string]any
projectsGetFunc func(ctx context.Context) (map[int64]string, error)
}

// WithConfig can be passed into LoadAuthorizer to pass in driver specific configuration.
func WithConfig(c map[string]any) func(*Opts) {
return func(o *Opts) {
o.config = c
}
}

// UserAccess struct for permission checks.
type UserAccess struct {
Admin bool
Projects map[string][]string
// WithProjectsGetFunc should be passed into LoadAuthorizer when DriverRBAC is used.
func WithProjectsGetFunc(f func(ctx context.Context) (map[int64]string, error)) func(*Opts) {
return func(o *Opts) {
o.projectsGetFunc = f
}
}

func LoadAuthorizer(name string, config map[string]any, logger logger.Logger, projectsGetFunc func() (map[int64]string, error)) (Authorizer, error) {
driverFunc, ok := authorizers[name]
// LoadAuthorizer instantiates, configures, and initialises an Authorizer.
func LoadAuthorizer(ctx context.Context, driver string, logger logger.Logger, certificateCache *certificate.Cache, options ...func(opts *Opts)) (Authorizer, error) {
opts := &Opts{}
for _, o := range options {
o(opts)
}

driverFunc, ok := authorizers[driver]
if !ok {
return nil, ErrUnknownDriver
}

d := driverFunc()
d.init(name, config, logger, projectsGetFunc)
err := d.init(driver, logger)
if err != nil {
return nil, fmt.Errorf("Failed to initialize authorizer: %w", err)
}

err := d.load()
err = d.load(ctx, certificateCache, *opts)
if err != nil {
return nil, err
return nil, fmt.Errorf("Failed to load authorizer: %w", err)
}

return d, nil
Expand Down
Loading