Skip to content

Commit

Permalink
[v16] Workload Identity: Add minimally viable implementation of Issue…
Browse files Browse the repository at this point in the history
…WorkloadIdentity RPC (#50379)

* Add MVP implementation of IssueWorkloadIdentity endpoint

* Add experiment flag

* Fix TTL shadowing

* Support some non-string attributes for rules and templatin

* Adjust regex with @timothyb89 's suggestions

* Add note on deny rules

* Fix for backport to v16
  • Loading branch information
strideynet authored Dec 20, 2024
1 parent b2ec964 commit 2755868
Show file tree
Hide file tree
Showing 7 changed files with 1,333 additions and 1 deletion.
17 changes: 17 additions & 0 deletions lib/auth/grpcserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -5230,6 +5230,23 @@ func NewGRPCServer(cfg GRPCServerConfig) (*GRPCServer, error) {
}
workloadidentityv1pb.RegisterWorkloadIdentityResourceServiceServer(server, workloadIdentityResourceService)

clusterName, err := cfg.AuthServer.GetClusterName()
if err != nil {
return nil, trace.Wrap(err, "getting cluster name")
}
workloadIdentityIssuanceService, err := workloadidentityv1.NewIssuanceService(&workloadidentityv1.IssuanceServiceConfig{
Authorizer: cfg.Authorizer,
Cache: cfg.AuthServer.Cache,
Emitter: cfg.Emitter,
Clock: cfg.AuthServer.GetClock(),
KeyStore: cfg.AuthServer.keyStore,
ClusterName: clusterName.GetClusterName(),
})
if err != nil {
return nil, trace.Wrap(err, "creating workload identity issuance service")
}
workloadidentityv1pb.RegisterWorkloadIdentityIssuanceServiceServer(server, workloadIdentityIssuanceService)

dbObjectImportRuleService, err := dbobjectimportrulev1.NewDatabaseObjectImportRuleService(dbobjectimportrulev1.DatabaseObjectImportRuleServiceConfig{
Authorizer: cfg.Authorizer,
Backend: cfg.AuthServer.Services,
Expand Down
35 changes: 34 additions & 1 deletion lib/auth/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -1324,11 +1324,38 @@ func CreateUser(ctx context.Context, clt clt, username string, roles ...types.Ro
return created, trace.Wrap(err)
}

// createUserAndRoleOptions is a set of options for CreateUserAndRole
type createUserAndRoleOptions struct {
mutateUser []func(user types.User)
mutateRole []func(role types.Role)
}

// CreateUserAndRoleOption is a functional option for CreateUserAndRole
type CreateUserAndRoleOption func(*createUserAndRoleOptions)

// WithUserMutator sets a function that will be called to mutate the user before it is created
func WithUserMutator(mutate ...func(user types.User)) CreateUserAndRoleOption {
return func(o *createUserAndRoleOptions) {
o.mutateUser = append(o.mutateUser, mutate...)
}
}

// WithRoleMutator sets a function that will be called to mutate the role before it is created
func WithRoleMutator(mutate ...func(role types.Role)) CreateUserAndRoleOption {
return func(o *createUserAndRoleOptions) {
o.mutateRole = append(o.mutateRole, mutate...)
}
}

// CreateUserAndRole creates user and role and assigns role to a user, used in tests
// If allowRules is nil, the role has admin privileges.
// If allowRules is not-nil, then the rules associated with the role will be
// replaced with those specified.
func CreateUserAndRole(clt clt, username string, allowedLogins []string, allowRules []types.Rule) (types.User, types.Role, error) {
func CreateUserAndRole(clt clt, username string, allowedLogins []string, allowRules []types.Rule, opts ...CreateUserAndRoleOption) (types.User, types.Role, error) {
o := createUserAndRoleOptions{}
for _, opt := range opts {
opt(&o)
}
ctx := context.TODO()
user, err := types.NewUser(username)
if err != nil {
Expand All @@ -1340,13 +1367,19 @@ func CreateUserAndRole(clt clt, username string, allowedLogins []string, allowRu
if allowRules != nil {
role.SetRules(types.Allow, allowRules)
}
for _, mutate := range o.mutateRole {
mutate(role)
}

upsertedRole, err := clt.UpsertRole(ctx, role)
if err != nil {
return nil, nil, trace.Wrap(err)
}

user.AddRole(upsertedRole.GetName())
for _, mutate := range o.mutateUser {
mutate(user)
}
created, err := clt.UpsertUser(ctx, user)
if err != nil {
return nil, nil, trace.Wrap(err)
Expand Down
41 changes: 41 additions & 0 deletions lib/auth/machineid/workloadidentityv1/experiment/experiment.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Teleport
// Copyright (C) 2024 Gravitational, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

package experiment

import (
"os"
"sync"
)

var mu sync.Mutex

var experimentEnabled = os.Getenv("TELEPORT_WORKLOAD_IDENTITY_UX_EXPERIMENT") == "1"

// Enabled returns true if the workload identity UX experiment is
// enabled.
func Enabled() bool {
mu.Lock()
defer mu.Unlock()
return experimentEnabled
}

// SetEnabled sets the experiment enabled flag.
func SetEnabled(enabled bool) {
mu.Lock()
defer mu.Unlock()
experimentEnabled = enabled
}
Loading

0 comments on commit 2755868

Please sign in to comment.