Skip to content

Commit

Permalink
Add support for a policy resource to Teleport (#17220)
Browse files Browse the repository at this point in the history
* add workings for policy resource

* add grpc defs for create/get policy

* policy resource plumbing

* fix some bugs & add tctl get command

* add listing code

* use a custom api instead of listresources

* rename ListPolicies to GetPolicies

* update allow/deny/options to be a map of scopes instead

* keep option a nonmap

* trim policy def

* touchups

* add rbac checks

* revert e ref

* rename
  • Loading branch information
xacrimon authored Oct 26, 2022
1 parent 6d0b1c3 commit 9d483e5
Show file tree
Hide file tree
Showing 16 changed files with 3,646 additions and 1,880 deletions.
31 changes: 31 additions & 0 deletions api/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -2868,3 +2868,34 @@ func (c *Client) UpsertClusterAlert(ctx context.Context, alert types.ClusterAler
}, c.callOpts...)
return trail.FromGRPC(err)
}

// CreatePolicy creates a new policy resource.
func (c *Client) CreatePolicy(ctx context.Context, policy types.Policy) error {
_, err := c.grpc.CreatePolicy(ctx, policy.(*types.AccessPolicyV1), c.callOpts...)
return trail.FromGRPC(err)
}

// GetPolicy fetches a policy resource by name.
func (c *Client) GetPolicy(ctx context.Context, name string) (types.Policy, error) {
resp, err := c.grpc.GetPolicy(ctx, &proto.GetPolicyRequest{Name: name}, c.callOpts...)
if err != nil {
return nil, trail.FromGRPC(err)
}

return resp, nil
}

// GetPolicies lists policies in the cluster.
func (c *Client) GetPolicies(ctx context.Context) ([]types.Policy, error) {
resp, err := c.grpc.GetPolicies(ctx, &emptypb.Empty{}, c.callOpts...)
if err != nil {
return nil, trail.FromGRPC(err)
}

policies := make([]types.Policy, len(resp.Policies))
for i, p := range resp.Policies {
policies[i] = p
}

return policies, nil
}
1,862 changes: 1,178 additions & 684 deletions api/client/proto/authservice.pb.go

Large diffs are not rendered by default.

17 changes: 17 additions & 0 deletions api/proto/teleport/legacy/client/proto/authservice.proto
Original file line number Diff line number Diff line change
Expand Up @@ -1892,6 +1892,16 @@ message AppendDiagnosticTraceRequest {
types.ConnectionDiagnosticTrace Trace = 2 [(gogoproto.jsontag) = "trace"];
}

// GetPolicyRequest is a request for a policy resource.
message GetPolicyRequest {
string Name = 1 [(gogoproto.jsontag) = "name"];
}

// GetPoliciesResponse is a response containing a list of policies.
message GetPoliciesResponse {
repeated types.AccessPolicyV1 Policies = 1 [(gogoproto.jsontag) = "policies"];
}

// AuthService is authentication/authorization service implementation
service AuthService {
// InventoryControlStream is the per-instance stream used to advertise teleport instance
Expand Down Expand Up @@ -1992,6 +2002,13 @@ service AuthService {
// GetBotUsers gets all users with bot labels.
rpc GetBotUsers(GetBotUsersRequest) returns (stream types.UserV2);

// CreatePolicy creates a new policy resource.
rpc CreatePolicy(types.AccessPolicyV1) returns (google.protobuf.Empty);
// GetPolicy fetches a policy resource by name.
rpc GetPolicy(GetPolicyRequest) returns (types.AccessPolicyV1);
// GetPolicies lists policies in the cluster.
rpc GetPolicies(google.protobuf.Empty) returns (GetPoliciesResponse);

// GetUser gets a user resource by name.
rpc GetUser(GetUserRequest) returns (types.UserV2);
// GetCurrentUser returns current user as seen by the server.
Expand Down
29 changes: 29 additions & 0 deletions api/proto/teleport/legacy/types/types.proto
Original file line number Diff line number Diff line change
Expand Up @@ -2096,6 +2096,35 @@ message CertExtension {
string Value = 4 [(gogoproto.jsontag) = "value"];
}

// AccessPolicyV1 is a predicate policy used for RBAC
message AccessPolicyV1 {
// Kind is a resource kind
string Kind = 1 [(gogoproto.jsontag) = "kind"];
// SubKind is an optional resource sub kind, used in some resources
string SubKind = 2 [(gogoproto.jsontag) = "sub_kind,omitempty"];
// Version is version
string Version = 3 [(gogoproto.jsontag) = "version"];
// Metadata is resource metadata
Metadata Metadata = 4 [
(gogoproto.nullable) = false,
(gogoproto.jsontag) = "metadata"
];
// Spec is a policy specification.
AccessPolicySpecV1 Spec = 5 [
(gogoproto.nullable) = false,
(gogoproto.jsontag) = "spec"
];
}

// AccessPolicySpecV1 is a predicate policy specification used for RBAC, not dissimilar to Role.
message AccessPolicySpecV1 {
// Allow contains a map of authentication contexts such as "node" to a map of allow predicate expressions.
map<string, string> Allow = 1 [(gogoproto.jsontag) = "allow,omitempty"];

// Deny contains scopes mapping to predicate expressions as above but the expressions are instead in deny form.
map<string, string> Deny = 2 [(gogoproto.jsontag) = "deny,omitempty"];
}

// RoleConditions is a set of conditions that must all match to be allowed or
// denied access.
message RoleConditions {
Expand Down
2 changes: 1 addition & 1 deletion api/types/access_request.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ type AccessRequest interface {
SetDryRun(bool)
}

// NewAccessRequest assembles an AccessRequest resource.
// Request assembles an AccessRequest resource.
func NewAccessRequest(name string, user string, roles ...string) (AccessRequest, error) {
return NewAccessRequestWithResources(name, user, roles, []ResourceID{})
}
Expand Down
3 changes: 3 additions & 0 deletions api/types/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,9 @@ const (
// KindClusterAlert is a resource that conveys a cluster-level alert message.
KindClusterAlert = "cluster_alert"

// KindAccessPolicy is an RBAC policy resource.
KindAccessPolicy = "access_policy"

// V5 is the fifth version of resources.
V5 = "v5"

Expand Down
118 changes: 118 additions & 0 deletions api/types/policy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/*
Copyright 2022 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package types

import (
"time"

"github.com/gravitational/trace"
)

// AccessPolicyV1 is a predicate policy used for RBAC, similar to rule but uses predicate language.
type Policy interface {
// Resource provides common resource properties
Resource
// GetAllow returns a list of allow expressions grouped by scope.
GetAllow() map[string]string
// GetDeny returns a list of deny expressions grouped by scope.
GetDeny() map[string]string
}

// GetVersion returns resource version
func (c *AccessPolicyV1) GetVersion() string {
return c.Version
}

// GetKind returns resource kind
func (c *AccessPolicyV1) GetKind() string {
return c.Kind
}

// GetSubKind returns resource sub kind
func (c *AccessPolicyV1) GetSubKind() string {
return c.SubKind
}

// SetSubKind sets resource subkind
func (c *AccessPolicyV1) SetSubKind(s string) {
c.SubKind = s
}

// GetResourceID returns resource ID
func (c *AccessPolicyV1) GetResourceID() int64 {
return c.Metadata.ID
}

// SetResourceID sets resource ID
func (c *AccessPolicyV1) SetResourceID(id int64) {
c.Metadata.ID = id
}

// setStaticFields sets static resource header and metadata fields.
func (c *AccessPolicyV1) setStaticFields() {
c.Kind = KindAccessPolicy
c.Version = V1
}

// CheckAndSetDefaults checks and sets default values
func (c *AccessPolicyV1) CheckAndSetDefaults() error {
c.setStaticFields()
if err := c.Metadata.CheckAndSetDefaults(); err != nil {
return trace.Wrap(err)
}
return nil
}

// GetMetadata returns object metadata
func (c *AccessPolicyV1) GetMetadata() Metadata {
return c.Metadata
}

// SetMetadata sets remote cluster metatada
func (c *AccessPolicyV1) SetMetadata(meta Metadata) {
c.Metadata = meta
}

// SetExpiry sets expiry time for the object
func (c *AccessPolicyV1) SetExpiry(expires time.Time) {
c.Metadata.SetExpiry(expires)
}

// Expiry returns object expiry setting
func (c *AccessPolicyV1) Expiry() time.Time {
return c.Metadata.Expiry()
}

// GetName returns the name of the RemoteCluster.
func (c *AccessPolicyV1) GetName() string {
return c.Metadata.Name
}

// SetName sets the name of the RemoteCluster.
func (c *AccessPolicyV1) SetName(e string) {
c.Metadata.Name = e
}

// GetAllow returns a list of allow expressions grouped by scope.
func (c *AccessPolicyV1) GetAllow() map[string]string {
return c.Spec.Allow
}

// GetDeny returns a list of deny expressions grouped by scope.
func (c *AccessPolicyV1) GetDeny() map[string]string {
return c.Spec.Deny
}
Loading

0 comments on commit 9d483e5

Please sign in to comment.