feat: Add initial AuthzQuerier implementation (#5919)

feat: Add initial AuthzQuerier implementation
- Adds package database/dbauthz that adds a database.Store implementation where each method goes through AuthZ checks
- Implements all database.Store methods on AuthzQuerier
- Updates and fixes unit tests where required
- Updates coderd initialization to use AuthzQuerier if codersdk.ExperimentAuthzQuerier is enabled
This commit is contained in:
Steven Masley
2023-02-14 14:27:06 +00:00
committed by GitHub
parent ebdfdc749d
commit 6fb8aff6d0
59 changed files with 5013 additions and 136 deletions
+6 -11
View File
@@ -12,7 +12,6 @@ import (
"testing"
"time"
"github.com/coder/coder/cryptorand"
"github.com/go-chi/chi/v5"
"github.com/google/uuid"
"github.com/moby/moby/pkg/namesgenerator"
@@ -20,8 +19,9 @@ import (
"github.com/stretchr/testify/require"
"golang.org/x/xerrors"
"github.com/coder/coder/cryptorand"
"github.com/coder/coder/coderd"
"github.com/coder/coder/coderd/database/dbfake"
"github.com/coder/coder/coderd/rbac"
"github.com/coder/coder/coderd/rbac/regosql"
"github.com/coder/coder/codersdk"
@@ -30,12 +30,6 @@ import (
)
func AGPLRoutes(a *AuthTester) (map[string]string, map[string]RouteCheck) {
// For any route using SQL filters, we need to know if the database is an
// in memory fake. This is because the in memory fake does not use SQL, and
// still uses rego. So this boolean indicates how to assert the expected
// behavior.
_, isMemoryDB := a.api.Database.(dbfake.FakeDatabase)
// Some quick reused objects
workspaceRBACObj := rbac.ResourceWorkspace.WithID(a.Workspace.ID).InOrg(a.Organization.ID).WithOwner(a.Workspace.OwnerID.String())
workspaceExecObj := rbac.ResourceWorkspaceExecution.WithID(a.Workspace.ID).InOrg(a.Organization.ID).WithOwner(a.Workspace.OwnerID.String())
@@ -269,16 +263,17 @@ func AGPLRoutes(a *AuthTester) (map[string]string, map[string]RouteCheck) {
"POST:/api/v2/workspaces/{workspace}/builds": {StatusCode: http.StatusBadRequest, NoAuthorize: true},
"POST:/api/v2/organizations/{organization}/templateversions": {StatusCode: http.StatusBadRequest, NoAuthorize: true},
// Endpoints that use the SQLQuery filter.
// For any route using SQL filters, we do not check authorization.
// This is because the in memory fake does not use SQL.
"GET:/api/v2/workspaces/": {
StatusCode: http.StatusOK,
NoAuthorize: !isMemoryDB,
NoAuthorize: true,
AssertAction: rbac.ActionRead,
AssertObject: rbac.ResourceWorkspace,
},
"GET:/api/v2/organizations/{organization}/templates": {
StatusCode: http.StatusOK,
NoAuthorize: !isMemoryDB,
NoAuthorize: true,
AssertAction: rbac.ActionRead,
AssertObject: rbac.ResourceTemplate,
},
+6
View File
@@ -2,15 +2,21 @@ package coderdtest_test
import (
"context"
"os"
"strings"
"testing"
"github.com/stretchr/testify/require"
"github.com/coder/coder/coderd/coderdtest"
"github.com/coder/coder/coderd/rbac"
"github.com/coder/coder/codersdk"
)
func TestAuthorizeAllEndpoints(t *testing.T) {
if strings.Contains(os.Getenv("CODER_EXPERIMENTS_TEST"), string(codersdk.ExperimentAuthzQuerier)) {
t.Skip("Skipping TestAuthorizeAllEndpoints for authz_querier experiment")
}
t.Parallel()
client, _, api := coderdtest.NewWithAPI(t, &coderdtest.Options{
// Required for any subdomain-based proxy tests to pass.
+9 -6
View File
@@ -35,6 +35,7 @@ import (
"github.com/golang-jwt/jwt"
"github.com/google/uuid"
"github.com/moby/moby/pkg/namesgenerator"
"github.com/prometheus/client_golang/prometheus"
"github.com/spf13/afero"
"github.com/spf13/pflag"
"github.com/stretchr/testify/assert"
@@ -58,6 +59,7 @@ import (
"github.com/coder/coder/coderd/autobuild/executor"
"github.com/coder/coder/coderd/awsidentity"
"github.com/coder/coder/coderd/database"
"github.com/coder/coder/coderd/database/dbauthz"
"github.com/coder/coder/coderd/database/dbtestutil"
"github.com/coder/coder/coderd/gitauth"
"github.com/coder/coder/coderd/gitsshkey"
@@ -179,12 +181,13 @@ func NewOptions(t *testing.T, options *Options) (func(http.Handler), context.Can
options.Database, options.Pubsub = dbtestutil.NewDB(t)
}
// TODO: remove this once we're ready to enable authz querier by default.
if strings.Contains(os.Getenv("CODER_EXPERIMENTS_TEST"), "authz_querier") {
panic("Coming soon!")
// if options.Authorizer != nil {
// options.Authorizer = &RecordingAuthorizer{}
// }
// options.Database = authzquery.NewAuthzQuerier(options.Database, options.Authorizer)
if strings.Contains(os.Getenv("CODER_EXPERIMENTS_TEST"), string(codersdk.ExperimentAuthzQuerier)) {
if options.Authorizer == nil {
options.Authorizer = &RecordingAuthorizer{
Wrapped: rbac.NewAuthorizer(prometheus.NewRegistry()),
}
}
options.Database = dbauthz.New(options.Database, options.Authorizer, slogtest.Make(t, nil).Leveled(slog.LevelDebug))
}
if options.DeploymentConfig == nil {
options.DeploymentConfig = DeploymentConfig(t)