Repository: cdk8s-team/cdk8s-plus
Pull request #1522 (2022-12-15 19:09:21)

feat(role): create role bindings using imported service accounts
Resolves https://github.com/cdk8s-team/cdk8s-plus/issues/1517


Patch:
diff --git a/src/service-account.ts b/src/service-account.ts
index 3713d7a1..394bc07c 100644
--- a/src/service-account.ts
+++ b/src/service-account.ts
@@ -7,7 +7,7 @@ import * as secret from './secret';
 import { undefinedIfEmpty } from './utils';
 
 
-export interface IServiceAccount extends base.IResource {
+export interface IServiceAccount extends base.IResource, rb.ISubject {
 
 }
 
@@ -33,15 +33,36 @@ export interface ServiceAccountProps extends base.ResourceProps {
   readonly automountToken?: boolean;
 }
 
+export interface FromServiceAccountNameOptions {
+
+  /**
+   * The name of the namespace the service account belongs to.
+   *
+   * @default "default"
+   */
+  readonly namespaceName?: string;
+}
+
 class ImportedServiceAccount extends Construct implements IServiceAccount {
 
   private readonly _name: string;
+  private readonly _namespaceName: string;
 
   public readonly resourceType = 'serviceaccounts';
 
-  constructor(scope: Construct, id: string, name: string) {
+  constructor(scope: Construct, id: string, name: string, options: FromServiceAccountNameOptions = {}) {
     super(scope, id);
     this._name = name;
+    this._namespaceName = options.namespaceName ?? 'default';
+  }
+
+  public toSubjectConfiguration(): rb.SubjectConfiguration {
+    return {
+      kind: this.kind,
+      name: this.name,
+      apiGroup: this.apiGroup,
+      namespace: this._namespaceName,
+    };
   }
 
   public get name(): string {
@@ -83,9 +104,10 @@ export class ServiceAccount extends base.Resource implements IServiceAccount, rb
   /**
    * Imports a service account from the cluster as a reference.
    * @param name The name of the service account resource.
+   * @param options additional options.
    */
-  public static fromServiceAccountName(scope: Construct, id: string, name: string): IServiceAccount {
-    return new ImportedServiceAccount(scope, id, name);
+  public static fromServiceAccountName(scope: Construct, id: string, name: string, options: FromServiceAccountNameOptions = {}): IServiceAccount {
+    return new ImportedServiceAccount(scope, id, name, options);
   }
 
   /**


Test patch:
diff --git a/test/__snapshots__/service-account.test.ts.snap b/test/__snapshots__/service-account.test.ts.snap
index a4f6e63b..00ba800d 100644
--- a/test/__snapshots__/service-account.test.ts.snap
+++ b/test/__snapshots__/service-account.test.ts.snap
@@ -29,3 +29,36 @@ Array [
   },
 ]
 `;
+
+exports[`role can bind to imported 1`] = `
+Array [
+  Object {
+    "apiVersion": "rbac.authorization.k8s.io/v1",
+    "kind": "Role",
+    "metadata": Object {
+      "name": "test-role-c8eba390",
+    },
+    "rules": Array [],
+  },
+  Object {
+    "apiVersion": "rbac.authorization.k8s.io/v1",
+    "kind": "RoleBinding",
+    "metadata": Object {
+      "name": "rolebindingc8d4456c17d6b366ba98c773dfc8a963b7-c8f143a2",
+    },
+    "roleRef": Object {
+      "apiGroup": "rbac.authorization.k8s.io",
+      "kind": "Role",
+      "name": "test-role-c8eba390",
+    },
+    "subjects": Array [
+      Object {
+        "apiGroup": "",
+        "kind": "ServiceAccount",
+        "name": "sa-name",
+        "namespace": "kube-system",
+      },
+    ],
+  },
+]
+`;
diff --git a/test/service-account.test.ts b/test/service-account.test.ts
index 5e734da9..baebcc20 100644
--- a/test/service-account.test.ts
+++ b/test/service-account.test.ts
@@ -14,6 +14,21 @@ test('can grant permissions on imported', () => {
 
 });
 
+test('role can bind to imported', () => {
+
+  const chart = Testing.chart();
+  const role = new kplus.Role(chart, 'Role');
+
+  const sa = kplus.ServiceAccount.fromServiceAccountName(chart, 'ServiceAccount', 'sa-name', {
+    namespaceName: 'kube-system',
+  });
+
+  role.bind(sa);
+
+  expect(Testing.synth(chart)).toMatchSnapshot();
+
+});
+
 test('defaultChild', () => {
   const chart = Testing.chart();