Skip to content

Commit

Permalink
[v16] Add workload_identity_labels to RoleCondition (#50071) (#50136)
Browse files Browse the repository at this point in the history
* Add `workload_identity_labels` to RoleCondition (#50071)

* Add WorkloadIdentityLabels field to role

* Wire up access checker

* Add validation for new field

* Update CRDs

* Add to terraform provider

* Mispel some words to keep the republic happy

* Add WorkloadIdentityLabelsExpression

* Update Terraform provider

* Add to operator CRD

* PLS RUN CLA CHECK

* Backport `resource153ToResourceWithLabelsAdapter`
  • Loading branch information
strideynet authored Dec 12, 2024
1 parent 59b77f9 commit f1829a6
Show file tree
Hide file tree
Showing 17 changed files with 2,596 additions and 1,944 deletions.
12 changes: 12 additions & 0 deletions api/proto/teleport/legacy/types/types.proto
Original file line number Diff line number Diff line change
Expand Up @@ -3288,6 +3288,18 @@ message RoleConditions {
reserved "SAMLIdPServiceProviderLabels";
reserved 41; // removed saml_idp_service_provider_labels_expression in favor of using app_labels_expression.
reserved "SAMLIdPServiceProviderLabelsExpression";

// WorkloadIdentityLabels controls whether or not specific WorkloadIdentity
// resources can be invoked. Further authorization controls exist on the
// WorkloadIdentity resource itself.
wrappers.LabelValues WorkloadIdentityLabels = 44 [
(gogoproto.nullable) = false,
(gogoproto.jsontag) = "workload_identity_labels,omitempty",
(gogoproto.customtype) = "Labels"
];
// WorkloadIdentityLabelsExpression is a predicate expression used to
// allow/deny access to issuing a WorkloadIdentity.
string WorkloadIdentityLabelsExpression = 45 [(gogoproto.jsontag) = "workload_identity_labels_expression,omitempty"];
}

// SPIFFERoleCondition sets out which SPIFFE identities this role is allowed or
Expand Down
81 changes: 81 additions & 0 deletions api/types/resource_153.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"google.golang.org/protobuf/types/known/timestamppb"

headerv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/header/v1"
"github.com/gravitational/teleport/api/utils"
)

// ResourceMetadata is the smallest interface that defines a Teleport resource.
Expand Down Expand Up @@ -212,3 +213,83 @@ func (r *resource153ToLegacyAdapter) SetRevision(rev string) {
func (r *resource153ToLegacyAdapter) SetSubKind(subKind string) {
panic("interface Resource153 does not implement SetSubKind")
}

// Resource153ToResourceWithLabels wraps a [Resource153]-style resource in
// the legacy [Resource] and [ResourceWithLabels] interfaces.
//
// The same caveats that apply to [Resource153ToLegacy] apply.
func Resource153ToResourceWithLabels(r Resource153) ResourceWithLabels {
return &resource153ToResourceWithLabelsAdapter{
resource153ToLegacyAdapter{
inner: r,
},
}
}

// resource153ToResourceWithLabelsAdapter wraps a new-style resource in a
// type implementing the legacy resource interfaces
type resource153ToResourceWithLabelsAdapter struct {
resource153ToLegacyAdapter
}

// Origin implements ResourceWithLabels for the adapter.
func (r *resource153ToResourceWithLabelsAdapter) Origin() string {
m := r.inner.GetMetadata()
if m == nil {
return ""
}
return m.Labels[OriginLabel]
}

// SetOrigin implements ResourceWithLabels for the adapter.
func (r *resource153ToResourceWithLabelsAdapter) SetOrigin(origin string) {
m := r.inner.GetMetadata()
if m == nil {
return
}
m.Labels[OriginLabel] = origin
}

// GetLabel implements ResourceWithLabels for the adapter.
func (r *resource153ToResourceWithLabelsAdapter) GetLabel(key string) (value string, ok bool) {
m := r.inner.GetMetadata()
if m == nil {
return "", false
}
value, ok = m.Labels[key]
return
}

// GetAllLabels implements ResourceWithLabels for the adapter.
func (r *resource153ToResourceWithLabelsAdapter) GetAllLabels() map[string]string {
m := r.inner.GetMetadata()
if m == nil {
return nil
}
return m.Labels
}

// GetStaticLabels implements ResourceWithLabels for the adapter.
func (r *resource153ToResourceWithLabelsAdapter) GetStaticLabels() map[string]string {
return r.GetAllLabels()
}

// SetStaticLabels implements ResourceWithLabels for the adapter.
func (r *resource153ToResourceWithLabelsAdapter) SetStaticLabels(labels map[string]string) {
m := r.inner.GetMetadata()
if m == nil {
return
}
m.Labels = labels
}

// MatchSearch implements ResourceWithLabels for the adapter. If the underlying
// type exposes a MatchSearch method, this method will defer to that, otherwise
// it will match against the resource label values and name.
func (r *resource153ToResourceWithLabelsAdapter) MatchSearch(searchValues []string) bool {
if matcher, ok := r.inner.(interface{ MatchSearch([]string) bool }); ok {
return matcher.MatchSearch(searchValues)
}
fieldVals := append(utils.MapToStrings(r.GetAllLabels()), r.GetName())
return MatchSearch(fieldVals, searchValues, nil)
}
33 changes: 33 additions & 0 deletions api/types/role.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,13 @@ type Role interface {
// SetNodeLabels sets the map of node labels this role is allowed or denied access to.
SetNodeLabels(RoleConditionType, Labels)

// GetWorkloadIdentityLabels gets the map of node labels this role is
// allowed or denied access to.
GetWorkloadIdentityLabels(RoleConditionType) Labels
// SetWorkloadIdentityLabels sets the map of WorkloadIdentity labels this
// role is allowed or denied access to.
SetWorkloadIdentityLabels(RoleConditionType, Labels)

// GetAppLabels gets the map of app labels this role is allowed or denied access to.
GetAppLabels(RoleConditionType) Labels
// SetAppLabels sets the map of app labels this role is allowed or denied access to.
Expand Down Expand Up @@ -604,6 +611,25 @@ func (r *RoleV6) SetNodeLabels(rct RoleConditionType, labels Labels) {
}
}

// GetWorkloadIdentityLabels gets the map of WorkloadIdentity labels for
// allow or deny.
func (r *RoleV6) GetWorkloadIdentityLabels(rct RoleConditionType) Labels {
if rct == Allow {
return r.Spec.Allow.WorkloadIdentityLabels
}
return r.Spec.Deny.WorkloadIdentityLabels
}

// SetWorkloadIdentityLabels sets the map of WorkloadIdentity labels this role
// is allowed or denied access to.
func (r *RoleV6) SetWorkloadIdentityLabels(rct RoleConditionType, labels Labels) {
if rct == Allow {
r.Spec.Allow.WorkloadIdentityLabels = labels.Clone()
} else {
r.Spec.Deny.WorkloadIdentityLabels = labels.Clone()
}
}

// GetAppLabels gets the map of app labels this role is allowed or denied access to.
func (r *RoleV6) GetAppLabels(rct RoleConditionType) Labels {
if rct == Allow {
Expand Down Expand Up @@ -1225,6 +1251,7 @@ func (r *RoleV6) CheckAndSetDefaults() error {
r.Spec.Allow.DatabaseLabels,
r.Spec.Allow.WindowsDesktopLabels,
r.Spec.Allow.GroupLabels,
r.Spec.Allow.WorkloadIdentityLabels,
} {
if err := checkWildcardSelector(labels); err != nil {
return trace.Wrap(err)
Expand Down Expand Up @@ -1906,6 +1933,8 @@ func (r *RoleV6) GetLabelMatchers(rct RoleConditionType, kind string) (LabelMatc
return LabelMatchers{cond.WindowsDesktopLabels, cond.WindowsDesktopLabelsExpression}, nil
case KindUserGroup:
return LabelMatchers{cond.GroupLabels, cond.GroupLabelsExpression}, nil
case KindWorkloadIdentity:
return LabelMatchers{cond.WorkloadIdentityLabels, cond.WorkloadIdentityLabelsExpression}, nil
}
return LabelMatchers{}, trace.BadParameter("can't get label matchers for resource kind %q", kind)
}
Expand Down Expand Up @@ -1956,6 +1985,10 @@ func (r *RoleV6) SetLabelMatchers(rct RoleConditionType, kind string, labelMatch
cond.GroupLabels = labelMatchers.Labels
cond.GroupLabelsExpression = labelMatchers.Expression
return nil
case KindWorkloadIdentity:
cond.WorkloadIdentityLabels = labelMatchers.Labels
cond.WorkloadIdentityLabelsExpression = labelMatchers.Expression
return nil
}
return trace.BadParameter("can't set label matchers for resource kind %q", kind)
}
Expand Down
Loading

0 comments on commit f1829a6

Please sign in to comment.