-
Notifications
You must be signed in to change notification settings - Fork 36
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Role
, ClusterRole
, RoleBinding
, ClusterRoleBinding
L2s
#432
Conversation
Signed-off-by: Christopher Rybicki <rybickic@amazon.com>
Signed-off-by: github-actions <github-actions@github.com>
Signed-off-by: Christopher Rybicki <rybickic@amazon.com>
Suggestion for API: const role = new Role(this, 'Role', { namespace: 'default'});
role.grantList(Grantee.fromObjects(deployment, pod));
role.grantList(Grantee.fromKind(Kind.Secrets, Kind.Deployments));
role.grantList({
objects: [deployment, pod],
});
role.grantList({
kinds: ['secrets', 'deployments'],
});
const binding = role.bind(user1, group1);
binding.addSubject(serviceAccount); const role = new kplus.ClusterRole(chart, 'grafana-operator');
role.addRule({
apiGroups: [''],
resources: ['events'],
verbs: ['get', 'watch', 'list', 'create', 'delete', 'update', 'patch'],
});
role.addRule({
apiGroups: ['integreatly.org'],
resources: [
'grafanadashboards',
'grafanadatasources',
'grafanadatasources/status',
],
verbs: ['get', 'list', 'create', 'update', 'delete', 'deletecollection', 'watch'],
}); Would be: const role = new Role(this, 'Role');
role.grantGet(Kind.EVENTS);
role.grantWatch(Kind.EVENTS);
role.grantList(Kind.EVENTS);
role.grantGet(Kind.custom({ resources: 'grafanadashboards', 'grafanadatasources', apiGroup: 'integreatly.org'} |
Signed-off-by: Christopher Rybicki <rybickic@amazon.com>
Signed-off-by: Christopher Rybicki <rybickic@amazon.com>
Signed-off-by: Christopher Rybicki <rybickic@amazon.com>
Signed-off-by: Christopher Rybicki <rybickic@amazon.com>
Signed-off-by: Christopher Rybicki <rybickic@amazon.com>
99a5dee
to
4af9086
Compare
src/grants.ts
Outdated
/** | ||
* Combine multiple resource kinds into a single grantee that can be used in a | ||
* Role or ClusterRole. | ||
*/ | ||
public static fromKinds(...types: ResourceType[]): IGrantee { | ||
const apiGroups = normalizedArray(types | ||
.map(type => type.apiGroups) | ||
.flat(), | ||
); | ||
const resources = normalizedArray(types | ||
.map(type => type.resources) | ||
.filter((x): x is string[] => Boolean(x)) | ||
.flat(), | ||
); | ||
return { apiGroups, resources }; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't being used, since I designed ResourceType
to implement IGrantee
as is. Should I drop it?
Signed-off-by: Christopher Rybicki <rybickic@amazon.com>
@Chriscbr I think Both So, if we define a common interface: export interface IApiResource {
// mandatory, both pods and a single pod has this.
readonly apiGroup: string;
// optional - pods will have this
readonly type?: string;
// optional - a single will have this
readonly name?: string;
} Then, our export abstract class Resource extends Construct implements IResource, IApiResource { If we now make export class ApiResource implements IApiResource {
/**
* API resource information for Binding.
*/
public static readonly BINDING = new ApiResource({
apiGroups: [''],
resources: ['bindings'],
});
....
....
} We can change the allow methods to accept: public allow(verbs: string[], ...resources: IApiResource[]): void { And viola, we have the API we wanted: role.allowRead(deployment, kplus.ApiResource.SECRETS, kplus.ApiResource.PODS); Thoughts? |
Signed-off-by: Christopher Rybicki <rybickic@amazon.com>
Signed-off-by: Christopher Rybicki <rybickic@amazon.com>
Signed-off-by: Christopher Rybicki <rybickic@amazon.com>
Signed-off-by: Christopher Rybicki <rybickic@amazon.com>
Signed-off-by: Christopher Rybicki <rybickic@amazon.com>
277b2ed
to
8976f22
Compare
Signed-off-by: github-actions <github-actions@github.com>
Signed-off-by: Christopher Rybicki <rybickic@amazon.com>
Signed-off-by: Christopher Rybicki <rybickic@amazon.com>
Signed-off-by: Christopher Rybicki <rybickic@amazon.com>
Signed-off-by: Christopher Rybicki <rybickic@amazon.com>
Signed-off-by: Christopher Rybicki <rybickic@amazon.com>
Signed-off-by: Christopher Rybicki <rybickic@amazon.com>
Signed-off-by: Christopher Rybicki <rybickic@amazon.com>
Signed-off-by: Christopher Rybicki <rybickic@amazon.com>
Thanks for all of the feedback @iliapolo ! This should be ready for another review 🙂 |
Signed-off-by: Eli Polonsky <epolon@amazon.com>
Signed-off-by: Eli Polonsky <epolon@amazon.com>
Signed-off-by: github-actions <github-actions@github.com>
@Chriscbr Following our conversation, I think we need to take a somewhat different approach. We've been trying to optimize for code maintenance by creating a common `RoleBase` that gives us some common functionality between a `Role` and a `ClusterRole`. However, we should be optimizing for user experience. A `Role` can only define rules for resources, where as a `ClusterRole` can define rules both for resources and non-resources. Trying to express this inherent difference, while still keeping a common base class, is I think what gets us in trouble. The solution we came up with is to have a common `addResourceRule` method in the base class, and have `ClusterRole` add an `addNonResourceRule` method that will only apply to it. This will result in the following API: ```ts const role = new kplus.Role(...); role.addResourceRule(...); role.allow(...); const clusterRole = new kplus.Role(...); clusterRole.addResourceRule(...); clusterRole.addNonResourceRule(...); clusterRole.allow(...); ``` There are several problems with this: - Naming inconsistency (`addResourceRule` vs `allow` - even though both refer to resource rules). Note that if we change `addResourceRule -> addRule`, it won't be clear why `ClusterRole` has `addRule` and `addNonResourceRule`. - The `add` methods don't offer any capabilities that the `allow` method don't. It creates a situation where we have two API's offering the same thing - which is confusing. I'm not sure the `add` methods have merit in higher level API's, the whole point is to remove this bulky k8s structure. If users want to use the underlying structure instead, they can always escape hatch. If we focus on optimizing user experience for the common use-case, I think the API should look like this: ```ts const role = new kplus.Role(...); // allow reading a specific pod and all secrets role.allowGet(pod, ApiResource.SECRETS); const clusterRole = new kplus.ClusterRole(...); // allow reading a specific pod, all secrets, and the /healthz endpoint clusterRole.allowGet(pod, ApiResource.SECRETS, ApiEndpoint.of('/healthz')); ``` Note that a `Role` can be given only api resources, but a `ClusterRole` can be given non api resources as well, all with the same API. This PR adds an `ApiEndpoint` (this name is also used in k8s docs: *non-resource endpoints (like /healthz)*) interface that allows `ClusterRole` to accept everything it can. It also removes the `add` methods in favor of the existing `allow` ones. Note that the base was class was completely removed, which of course resulted in a some duplication, but I think its worth it for the flexibility it gives. #### Resources - https://octopus.com/blog/k8s-rbac-roles-and-bindings - https://kubernetes.io/docs/reference/access-authn-authz/rbac/
Signed-off-by: Eli Polonsky <epolon@amazon.com>
Signed-off-by: Eli Polonsky <epolon@amazon.com>
Role
, ClusterRole
, RoleBinding
, ClusterRoleBinding
L2s
💔 All backports failed
Manual backportTo create the backport manually run:
Questions ?Please refer to the Backport tool documentation |
…432) Fixes #24 Fixes #25 Fixes #26 Fixes #374 Adds Role and ClusterRole L2s with "allowXxx" methods that resemble those available in the AWS CDK. This allows you to write code like: ```ts import * as kplus from 'cdk8s-plus-23'; declare const deployment: kplus.Deployment; const role = new kplus.ClusterRole(chart, 'my-cluster-role'); role.allowRead(deployment, kplus.ApiResource.SECRETS, kplus.ApiResource.PODS); ``` ...where the "read" syntactic sugar grants permissions to the "get", "list", and "watch" commands. There are other allow commands available that offer more granularity if needed. RoleBinding and ClusterRoleBinding L2s have also been created, and they can be instantiated through their constructors, or created using the appropriate bind methods that will attach it to the role automatically: ```ts declare const role: kplus.Role; declare const clusterRole: kplus.ClusterRole; const user = new kplus.User({ name: 'alice@example.com' }); const group = new kplus.Group({ name: 'frontend-devs' }); role.bind(user, group); // creates a RoleBinding associated with the same namespace `role` was defined with clusterRole.bindInNamespace('development', user, group); // creates a RoleBinding associated with namespace "development" clusterRole.bind(user, group); // creates a ClusterRoleBinding, not associated with any namespace ``` Future work: - Add full `pod.grantRead(role)` and `Resources.fromTypes(ApiResource.POD).grantRead(role)` style APIs - Add type checking or validation to prevent adding namespaced resources to ClusterRole or cluster-wide resources to Role's etc. - Add more constants to `ApiResource` for granting permissions to [subresources](https://stackoverflow.com/questions/57872201/how-to-refer-to-all-subresources-in-a-role-definition) - Add convenience APIs for adding permissions to the [default roles](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#default-roles-and-role-bindings) using `aggregate-to-<default-role>` tags BREAKING CHANGE: The interface `Resources` is now named `ContainerResources`. Signed-off-by: Christopher Rybicki <rybickic@amazon.com> (cherry picked from commit aeaba6e) Signed-off-by: Eli Polonsky <epolon@amazon.com> # Conflicts: # .projen/tasks.json # package.json # src/ingress-v1beta1.ts
💚 All backports created successfully
Questions ?Please refer to the Backport tool documentation |
…432) Fixes #24 Fixes #25 Fixes #26 Fixes #374 Adds Role and ClusterRole L2s with "allowXxx" methods that resemble those available in the AWS CDK. This allows you to write code like: ```ts import * as kplus from 'cdk8s-plus-23'; declare const deployment: kplus.Deployment; const role = new kplus.ClusterRole(chart, 'my-cluster-role'); role.allowRead(deployment, kplus.ApiResource.SECRETS, kplus.ApiResource.PODS); ``` ...where the "read" syntactic sugar grants permissions to the "get", "list", and "watch" commands. There are other allow commands available that offer more granularity if needed. RoleBinding and ClusterRoleBinding L2s have also been created, and they can be instantiated through their constructors, or created using the appropriate bind methods that will attach it to the role automatically: ```ts declare const role: kplus.Role; declare const clusterRole: kplus.ClusterRole; const user = new kplus.User({ name: 'alice@example.com' }); const group = new kplus.Group({ name: 'frontend-devs' }); role.bind(user, group); // creates a RoleBinding associated with the same namespace `role` was defined with clusterRole.bindInNamespace('development', user, group); // creates a RoleBinding associated with namespace "development" clusterRole.bind(user, group); // creates a ClusterRoleBinding, not associated with any namespace ``` Future work: - Add full `pod.grantRead(role)` and `Resources.fromTypes(ApiResource.POD).grantRead(role)` style APIs - Add type checking or validation to prevent adding namespaced resources to ClusterRole or cluster-wide resources to Role's etc. - Add more constants to `ApiResource` for granting permissions to [subresources](https://stackoverflow.com/questions/57872201/how-to-refer-to-all-subresources-in-a-role-definition) - Add convenience APIs for adding permissions to the [default roles](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#default-roles-and-role-bindings) using `aggregate-to-<default-role>` tags BREAKING CHANGE: The interface `Resources` is now named `ContainerResources`. Signed-off-by: Christopher Rybicki <rybickic@amazon.com> (cherry picked from commit aeaba6e) Signed-off-by: Eli Polonsky <epolon@amazon.com> # Conflicts: # .projen/tasks.json # .projenrc.ts # package.json # src/ingress-v1beta1.ts
💚 All backports created successfully
Questions ?Please refer to the Backport tool documentation |
…432) (#685) * feat: `Role`, `ClusterRole`, `RoleBinding`, `ClusterRoleBinding` L2s (#432) Fixes #24 Fixes #25 Fixes #26 Fixes #374 Adds Role and ClusterRole L2s with "allowXxx" methods that resemble those available in the AWS CDK. This allows you to write code like: ```ts import * as kplus from 'cdk8s-plus-23'; declare const deployment: kplus.Deployment; const role = new kplus.ClusterRole(chart, 'my-cluster-role'); role.allowRead(deployment, kplus.ApiResource.SECRETS, kplus.ApiResource.PODS); ``` ...where the "read" syntactic sugar grants permissions to the "get", "list", and "watch" commands. There are other allow commands available that offer more granularity if needed. RoleBinding and ClusterRoleBinding L2s have also been created, and they can be instantiated through their constructors, or created using the appropriate bind methods that will attach it to the role automatically: ```ts declare const role: kplus.Role; declare const clusterRole: kplus.ClusterRole; const user = new kplus.User({ name: 'alice@example.com' }); const group = new kplus.Group({ name: 'frontend-devs' }); role.bind(user, group); // creates a RoleBinding associated with the same namespace `role` was defined with clusterRole.bindInNamespace('development', user, group); // creates a RoleBinding associated with namespace "development" clusterRole.bind(user, group); // creates a ClusterRoleBinding, not associated with any namespace ``` Future work: - Add full `pod.grantRead(role)` and `Resources.fromTypes(ApiResource.POD).grantRead(role)` style APIs - Add type checking or validation to prevent adding namespaced resources to ClusterRole or cluster-wide resources to Role's etc. - Add more constants to `ApiResource` for granting permissions to [subresources](https://stackoverflow.com/questions/57872201/how-to-refer-to-all-subresources-in-a-role-definition) - Add convenience APIs for adding permissions to the [default roles](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#default-roles-and-role-bindings) using `aggregate-to-<default-role>` tags BREAKING CHANGE: The interface `Resources` is now named `ContainerResources`. Signed-off-by: Christopher Rybicki <rybickic@amazon.com> (cherry picked from commit aeaba6e) Signed-off-by: Eli Polonsky <epolon@amazon.com> # Conflicts: # .projen/tasks.json # package.json # src/ingress-v1beta1.ts * chore: self mutation Signed-off-by: github-actions <github-actions@github.com> Co-authored-by: Christopher Rybicki <rybickic@amazon.com> Co-authored-by: github-actions <github-actions@github.com>
…432) (#686) * feat: `Role`, `ClusterRole`, `RoleBinding`, `ClusterRoleBinding` L2s (#432) Fixes #24 Fixes #25 Fixes #26 Fixes #374 Adds Role and ClusterRole L2s with "allowXxx" methods that resemble those available in the AWS CDK. This allows you to write code like: ```ts import * as kplus from 'cdk8s-plus-23'; declare const deployment: kplus.Deployment; const role = new kplus.ClusterRole(chart, 'my-cluster-role'); role.allowRead(deployment, kplus.ApiResource.SECRETS, kplus.ApiResource.PODS); ``` ...where the "read" syntactic sugar grants permissions to the "get", "list", and "watch" commands. There are other allow commands available that offer more granularity if needed. RoleBinding and ClusterRoleBinding L2s have also been created, and they can be instantiated through their constructors, or created using the appropriate bind methods that will attach it to the role automatically: ```ts declare const role: kplus.Role; declare const clusterRole: kplus.ClusterRole; const user = new kplus.User({ name: 'alice@example.com' }); const group = new kplus.Group({ name: 'frontend-devs' }); role.bind(user, group); // creates a RoleBinding associated with the same namespace `role` was defined with clusterRole.bindInNamespace('development', user, group); // creates a RoleBinding associated with namespace "development" clusterRole.bind(user, group); // creates a ClusterRoleBinding, not associated with any namespace ``` Future work: - Add full `pod.grantRead(role)` and `Resources.fromTypes(ApiResource.POD).grantRead(role)` style APIs - Add type checking or validation to prevent adding namespaced resources to ClusterRole or cluster-wide resources to Role's etc. - Add more constants to `ApiResource` for granting permissions to [subresources](https://stackoverflow.com/questions/57872201/how-to-refer-to-all-subresources-in-a-role-definition) - Add convenience APIs for adding permissions to the [default roles](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#default-roles-and-role-bindings) using `aggregate-to-<default-role>` tags BREAKING CHANGE: The interface `Resources` is now named `ContainerResources`. Signed-off-by: Christopher Rybicki <rybickic@amazon.com> (cherry picked from commit aeaba6e) Signed-off-by: Eli Polonsky <epolon@amazon.com> # Conflicts: # .projen/tasks.json # .projenrc.ts # package.json # src/ingress-v1beta1.ts * conflict Signed-off-by: Eli Polonsky <epolon@amazon.com> Co-authored-by: Christopher Rybicki <rybickic@amazon.com>
Fixes #24
Fixes #25
Fixes #26
Fixes #374
Adds Role and ClusterRole L2s with "allowXxx" methods that resemble those available in the AWS CDK. This allows you to write code like:
...where the "read" syntactic sugar grants permissions to the "get", "list", and "watch" commands. There are other allow commands available that offer more granularity if needed.
RoleBinding and ClusterRoleBinding L2s have also been created, and they can be instantiated through their constructors, or created using the appropriate bind methods that will attach it to the role automatically:
Future work:
pod.grantRead(role)
andResources.fromTypes(ApiResource.POD).grantRead(role)
style APIsApiResource
for granting permissions to subresourcesaggregate-to-<default-role>
tagsBREAKING CHANGE: The interface
Resources
is now namedContainerResources
.Signed-off-by: Christopher Rybicki rybickic@amazon.com