mirror of https://github.com/linkerd/linkerd2.git
113 lines
2.9 KiB
Go
113 lines
2.9 KiB
Go
package k8s
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
|
|
authV1 "k8s.io/api/authorization/v1"
|
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
|
"k8s.io/client-go/kubernetes"
|
|
)
|
|
|
|
// ResourceAuthz checks whether a given Kubernetes client is authorized to
|
|
// perform a given action.
|
|
func ResourceAuthz(
|
|
k8sClient kubernetes.Interface,
|
|
namespace, verb, group, version, resource, name string,
|
|
) error {
|
|
ssar := &authV1.SelfSubjectAccessReview{
|
|
Spec: authV1.SelfSubjectAccessReviewSpec{
|
|
ResourceAttributes: &authV1.ResourceAttributes{
|
|
Namespace: namespace,
|
|
Verb: verb,
|
|
Group: group,
|
|
Version: version,
|
|
Resource: resource,
|
|
Name: name,
|
|
},
|
|
},
|
|
}
|
|
|
|
result, err := k8sClient.
|
|
AuthorizationV1().
|
|
SelfSubjectAccessReviews().
|
|
Create(ssar)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return evaluateAccessReviewStatus(group, resource, result.Status)
|
|
}
|
|
|
|
// ResourceAuthzForUser checks whether a given user is authorized to perform a
|
|
// given action.
|
|
func ResourceAuthzForUser(
|
|
client kubernetes.Interface,
|
|
namespace, verb, group, version, resource, subresource, name, user string, userGroups []string) error {
|
|
sar := &authV1.SubjectAccessReview{
|
|
Spec: authV1.SubjectAccessReviewSpec{
|
|
User: user,
|
|
Groups: userGroups,
|
|
ResourceAttributes: &authV1.ResourceAttributes{
|
|
Namespace: namespace,
|
|
Verb: verb,
|
|
Group: group,
|
|
Version: version,
|
|
Resource: resource,
|
|
Subresource: subresource,
|
|
Name: name,
|
|
},
|
|
},
|
|
}
|
|
|
|
result, err := client.
|
|
AuthorizationV1().
|
|
SubjectAccessReviews().
|
|
Create(sar)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return evaluateAccessReviewStatus(group, resource, result.Status)
|
|
}
|
|
|
|
func evaluateAccessReviewStatus(group, resource string, status authV1.SubjectAccessReviewStatus) error {
|
|
if status.Allowed {
|
|
return nil
|
|
}
|
|
|
|
gk := schema.GroupKind{
|
|
Group: group,
|
|
Kind: resource,
|
|
}
|
|
if len(status.Reason) > 0 {
|
|
return fmt.Errorf("not authorized to access %s: %s", gk, status.Reason)
|
|
}
|
|
return fmt.Errorf("not authorized to access %s", gk)
|
|
}
|
|
|
|
// ServiceProfilesAccess checks whether the ServiceProfile CRD is installed
|
|
// on the cluster and the client is authorized to access ServiceProfiles.
|
|
func ServiceProfilesAccess(k8sClient kubernetes.Interface) error {
|
|
res, err := k8sClient.Discovery().ServerResourcesForGroupVersion(ServiceProfileAPIVersion)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if res.GroupVersion == ServiceProfileAPIVersion {
|
|
for _, apiRes := range res.APIResources {
|
|
if apiRes.Kind == ServiceProfileKind {
|
|
return ResourceAuthz(k8sClient, "", "list", "linkerd.io", "", "serviceprofiles", "")
|
|
}
|
|
}
|
|
}
|
|
|
|
return errors.New("ServiceProfile CRD not found")
|
|
}
|
|
|
|
// ClusterAccess verifies whether k8sClient is authorized to access all pods in
|
|
// all namespaces in the cluster.
|
|
func ClusterAccess(k8sClient kubernetes.Interface) error {
|
|
return ResourceAuthz(k8sClient, "", "list", "", "", "pods", "")
|
|
}
|