@p0security/cli 0.11.1 → 0.11.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/commands/__tests__/login.test.js +17 -0
  2. package/dist/commands/__tests__/login.test.js.map +1 -1
  3. package/dist/commands/__tests__/ls.test.js +4 -3
  4. package/dist/commands/__tests__/ls.test.js.map +1 -1
  5. package/dist/commands/__tests__/ssh.test.js +10 -5
  6. package/dist/commands/__tests__/ssh.test.js.map +1 -1
  7. package/dist/commands/kubeconfig.js +11 -15
  8. package/dist/commands/kubeconfig.js.map +1 -1
  9. package/dist/commands/login.js +11 -0
  10. package/dist/commands/login.js.map +1 -1
  11. package/dist/commands/ls.js +4 -6
  12. package/dist/commands/ls.js.map +1 -1
  13. package/dist/commands/shared/request.js +2 -2
  14. package/dist/commands/shared/request.js.map +1 -1
  15. package/dist/drivers/__mocks__/stdio.d.ts +14 -0
  16. package/dist/drivers/__mocks__/stdio.js +26 -0
  17. package/dist/drivers/__mocks__/stdio.js.map +1 -0
  18. package/dist/drivers/ansi.d.ts +8 -0
  19. package/dist/drivers/ansi.js +25 -0
  20. package/dist/drivers/ansi.js.map +1 -0
  21. package/dist/drivers/auth.d.ts +1 -0
  22. package/dist/drivers/auth.js +8 -4
  23. package/dist/drivers/auth.js.map +1 -1
  24. package/dist/drivers/stdio.d.ts +6 -5
  25. package/dist/drivers/stdio.js +50 -7
  26. package/dist/drivers/stdio.js.map +1 -1
  27. package/dist/plugins/aws/__tests__/utils.test.d.ts +1 -0
  28. package/dist/plugins/aws/__tests__/utils.test.js +82 -0
  29. package/dist/plugins/aws/__tests__/utils.test.js.map +1 -0
  30. package/dist/plugins/aws/ssh.js +45 -23
  31. package/dist/plugins/aws/ssh.js.map +1 -1
  32. package/dist/plugins/aws/types.d.ts +6 -4
  33. package/dist/plugins/aws/utils.d.ts +20 -0
  34. package/dist/plugins/aws/utils.js +54 -0
  35. package/dist/plugins/aws/utils.js.map +1 -0
  36. package/dist/plugins/google/ssh-key.js +9 -1
  37. package/dist/plugins/google/ssh-key.js.map +1 -1
  38. package/dist/plugins/google/ssh.js +61 -28
  39. package/dist/plugins/google/ssh.js.map +1 -1
  40. package/dist/plugins/kubeconfig/index.d.ts +2 -2
  41. package/dist/plugins/kubeconfig/index.js +17 -14
  42. package/dist/plugins/kubeconfig/index.js.map +1 -1
  43. package/dist/plugins/kubeconfig/types.d.ts +9 -8
  44. package/dist/plugins/ssh/index.js +55 -86
  45. package/dist/plugins/ssh/index.js.map +1 -1
  46. package/dist/types/ssh.d.ts +28 -13
  47. package/package.json +3 -3
@@ -9,15 +9,25 @@ This file is part of @p0security/cli
9
9
 
10
10
  You should have received a copy of the GNU General Public License along with @p0security/cli. If not, see <https://www.gnu.org/licenses/>.
11
11
  **/
12
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
13
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
14
+ return new (P || (P = Promise))(function (resolve, reject) {
15
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
16
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
17
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
18
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
19
+ });
20
+ };
12
21
  Object.defineProperty(exports, "__esModule", { value: true });
13
- exports.Ansi = exports.print2 = exports.print1 = void 0;
22
+ exports.spinUntil = exports.clear2 = exports.reset2 = exports.print2 = exports.print1 = void 0;
14
23
  /** Functions to handle stdio
15
24
  *
16
25
  * These are essentially wrappers around console.foo, but allow for
17
26
  * - Better testing
18
27
  * - Later redirection / duplication
19
28
  */
20
- const lodash_1 = require("lodash");
29
+ const util_1 = require("../util");
30
+ const ansi_1 = require("./ansi");
21
31
  /** Used to output machine-readable text to stdout
22
32
  *
23
33
  * In general this should not be used for text meant to be consumed
@@ -37,10 +47,43 @@ function print2(message) {
37
47
  console.error(message);
38
48
  }
39
49
  exports.print2 = print2;
40
- const AnsiCodes = {
41
- Reset: "00",
42
- Dim: "02",
43
- Yellow: "33",
50
+ /** Resets the terminal cursor to the beginning of the line */
51
+ function reset2() {
52
+ process.stderr.write((0, ansi_1.Ansi)("0G"));
53
+ }
54
+ exports.reset2 = reset2;
55
+ /** Clears the current terminal line */
56
+ function clear2() {
57
+ // Replaces text with spaces
58
+ process.stderr.write((0, ansi_1.Ansi)("2K"));
59
+ reset2();
60
+ }
61
+ exports.clear2 = clear2;
62
+ const Spin = {
63
+ items: ["⠇", "⠋", "⠙", "⠸", "⠴", "⠦"],
64
+ delayMs: 200,
44
65
  };
45
- exports.Ansi = (0, lodash_1.mapValues)(AnsiCodes, (v) => `\u001b[${v}m`);
66
+ /** Prints a Unicode spinner until a promise resolves */
67
+ const spinUntil = (message, promise) => __awaiter(void 0, void 0, void 0, function* () {
68
+ let isDone = false;
69
+ let ix = 0;
70
+ // 'catch' here just prevents UncaughtExceptionError; errors are sent to caller
71
+ // on function return
72
+ void promise.finally(() => (isDone = true)).catch(() => { });
73
+ while (!isDone) {
74
+ yield (0, util_1.sleep)(Spin.delayMs);
75
+ if (isDone)
76
+ break;
77
+ clear2();
78
+ process.stderr.write(ansi_1.AnsiSgr.Green +
79
+ Spin.items[ix % Spin.items.length] +
80
+ " " +
81
+ message +
82
+ ansi_1.AnsiSgr.Reset);
83
+ ix++;
84
+ }
85
+ clear2();
86
+ return yield promise;
87
+ });
88
+ exports.spinUntil = spinUntil;
46
89
  //# sourceMappingURL=stdio.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"stdio.js","sourceRoot":"","sources":["../../src/drivers/stdio.ts"],"names":[],"mappings":";AAAA;;;;;;;;;GASG;;;AAEH;;;;;GAKG;AACH,mCAAmC;AAEnC;;;;GAIG;AACH,SAAgB,MAAM,CAAC,OAAY;IACjC,sCAAsC;IACtC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AACvB,CAAC;AAHD,wBAGC;AAED;;;GAGG;AACH,SAAgB,MAAM,CAAC,OAAY;IACjC,sCAAsC;IACtC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;AACzB,CAAC;AAHD,wBAGC;AAED,MAAM,SAAS,GAAG;IAChB,KAAK,EAAE,IAAI;IACX,GAAG,EAAE,IAAI;IACT,MAAM,EAAE,IAAI;CACJ,CAAC;AAEE,QAAA,IAAI,GAAG,IAAA,kBAAS,EAAC,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC"}
1
+ {"version":3,"file":"stdio.js","sourceRoot":"","sources":["../../src/drivers/stdio.ts"],"names":[],"mappings":";AAAA;;;;;;;;;GASG;;;;;;;;;;;;AAEH;;;;;GAKG;AACH,kCAAgC;AAChC,iCAAuC;AAEvC;;;;GAIG;AACH,SAAgB,MAAM,CAAC,OAAY;IACjC,sCAAsC;IACtC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AACvB,CAAC;AAHD,wBAGC;AAED;;;GAGG;AACH,SAAgB,MAAM,CAAC,OAAY;IACjC,sCAAsC;IACtC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;AACzB,CAAC;AAHD,wBAGC;AAED,8DAA8D;AAC9D,SAAgB,MAAM;IACpB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAA,WAAI,EAAC,IAAI,CAAC,CAAC,CAAC;AACnC,CAAC;AAFD,wBAEC;AAED,uCAAuC;AACvC,SAAgB,MAAM;IACpB,4BAA4B;IAC5B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAA,WAAI,EAAC,IAAI,CAAC,CAAC,CAAC;IACjC,MAAM,EAAE,CAAC;AACX,CAAC;AAJD,wBAIC;AAED,MAAM,IAAI,GAAG;IACX,KAAK,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;IACrC,OAAO,EAAE,GAAG;CACb,CAAC;AAEF,wDAAwD;AACjD,MAAM,SAAS,GAAG,CAAU,OAAe,EAAE,OAAmB,EAAE,EAAE;IACzE,IAAI,MAAM,GAAG,KAAK,CAAC;IACnB,IAAI,EAAE,GAAG,CAAC,CAAC;IACX,+EAA+E;IAC/E,qBAAqB;IACrB,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IAC5D,OAAO,CAAC,MAAM,EAAE;QACd,MAAM,IAAA,YAAK,EAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC1B,IAAI,MAAM;YAAE,MAAM;QAClB,MAAM,EAAE,CAAC;QACT,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,cAAO,CAAC,KAAK;YACX,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;YAClC,GAAG;YACH,OAAO;YACP,cAAO,CAAC,KAAK,CAChB,CAAC;QACF,EAAE,EAAE,CAAC;KACN;IACD,MAAM,EAAE,CAAC;IACT,OAAO,MAAM,OAAO,CAAC;AACvB,CAAC,CAAA,CAAC;AArBW,QAAA,SAAS,aAqBpB"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ /** Copyright © 2024-present P0 Security
4
+
5
+ This file is part of @p0security/cli
6
+
7
+ @p0security/cli is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 3 of the License.
8
+
9
+ @p0security/cli is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
10
+
11
+ You should have received a copy of the GNU General Public License along with @p0security/cli. If not, see <https://www.gnu.org/licenses/>.
12
+ **/
13
+ const utils_1 = require("../utils");
14
+ describe("parseArn() function", () => {
15
+ it.each([
16
+ "badarn:aws:ec2:us-east-1:123456789012:vpc/vpc-0e9801d129EXAMPLE",
17
+ ":aws:ec2:us-east-1:123456789012:vpc/vpc-0e9801d129EXAMPLE",
18
+ "arn:aws:ec2:us-east-1:123456789012", // Too few elements
19
+ ])('Raises an "Invalid ARN" error', (arn) => {
20
+ expect(() => (0, utils_1.parseArn)(arn)).toThrow("Invalid AWS ARN");
21
+ });
22
+ it("Parses a valid ARN with all fields correctly", () => {
23
+ const arn = "arn:aws:ec2:us-east-1:123456789012:vpc/vpc-0e9801d129EXAMPLE";
24
+ const parsed = (0, utils_1.parseArn)(arn);
25
+ expect(parsed).toEqual({
26
+ partition: "aws",
27
+ service: "ec2",
28
+ region: "us-east-1",
29
+ accountId: "123456789012",
30
+ resource: "vpc/vpc-0e9801d129EXAMPLE",
31
+ });
32
+ });
33
+ it("Parses a valid ARN with colons in the resource correctly", () => {
34
+ // Note: This is not the format we would expect an EKS ARN to actually be in (it should
35
+ // use a / instead of a : in the resource); this is just for unit testing purposes.
36
+ const arn = "arn:aws:eks:us-west-2:123456789012:cluster:my-testing-cluster";
37
+ const parsed = (0, utils_1.parseArn)(arn);
38
+ expect(parsed).toEqual({
39
+ partition: "aws",
40
+ service: "eks",
41
+ region: "us-west-2",
42
+ accountId: "123456789012",
43
+ resource: "cluster:my-testing-cluster",
44
+ });
45
+ });
46
+ it("Parses a valid ARN with no region correctly", () => {
47
+ const arn = "arn:aws:iam::123456789012:user/johndoe";
48
+ const parsed = (0, utils_1.parseArn)(arn);
49
+ expect(parsed).toEqual({
50
+ partition: "aws",
51
+ service: "iam",
52
+ region: "",
53
+ accountId: "123456789012",
54
+ resource: "user/johndoe",
55
+ });
56
+ });
57
+ it("Parses a valid ARN with no account ID correctly", () => {
58
+ // Note: This is not a valid SNS ARN; they would ordinarily have an account ID. This is
59
+ // just for unit testing purposes.
60
+ const arn = "arn:aws-us-gov:sns:us-east-1::example-sns-topic-name";
61
+ const parsed = (0, utils_1.parseArn)(arn);
62
+ expect(parsed).toEqual({
63
+ partition: "aws-us-gov",
64
+ service: "sns",
65
+ region: "us-east-1",
66
+ accountId: "",
67
+ resource: "example-sns-topic-name",
68
+ });
69
+ });
70
+ it("Parses a valid ARN with no region or account ID correctly", () => {
71
+ const arn = "arn:aws-cn:s3:::my-corporate-bucket";
72
+ const parsed = (0, utils_1.parseArn)(arn);
73
+ expect(parsed).toEqual({
74
+ partition: "aws-cn",
75
+ service: "s3",
76
+ region: "",
77
+ accountId: "",
78
+ resource: "my-corporate-bucket",
79
+ });
80
+ });
81
+ });
82
+ //# sourceMappingURL=utils.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.test.js","sourceRoot":"","sources":["../../../../src/plugins/aws/__tests__/utils.test.ts"],"names":[],"mappings":";;AAAA;;;;;;;;;GASG;AACH,oCAAoC;AAEpC,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE;IACnC,EAAE,CAAC,IAAI,CAAC;QACN,iEAAiE;QACjE,2DAA2D;QAC3D,oCAAoC,EAAE,mBAAmB;KAC1D,CAAC,CAAC,+BAA+B,EAAE,CAAC,GAAG,EAAE,EAAE;QAC1C,MAAM,CAAC,GAAG,EAAE,CAAC,IAAA,gBAAQ,EAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACtD,MAAM,GAAG,GAAG,8DAA8D,CAAC;QAE3E,MAAM,MAAM,GAAG,IAAA,gBAAQ,EAAC,GAAG,CAAC,CAAC;QAE7B,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;YACrB,SAAS,EAAE,KAAK;YAChB,OAAO,EAAE,KAAK;YACd,MAAM,EAAE,WAAW;YACnB,SAAS,EAAE,cAAc;YACzB,QAAQ,EAAE,2BAA2B;SACtC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0DAA0D,EAAE,GAAG,EAAE;QAClE,uFAAuF;QACvF,mFAAmF;QACnF,MAAM,GAAG,GAAG,+DAA+D,CAAC;QAE5E,MAAM,MAAM,GAAG,IAAA,gBAAQ,EAAC,GAAG,CAAC,CAAC;QAE7B,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;YACrB,SAAS,EAAE,KAAK;YAChB,OAAO,EAAE,KAAK;YACd,MAAM,EAAE,WAAW;YACnB,SAAS,EAAE,cAAc;YACzB,QAAQ,EAAE,4BAA4B;SACvC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,MAAM,GAAG,GAAG,wCAAwC,CAAC;QAErD,MAAM,MAAM,GAAG,IAAA,gBAAQ,EAAC,GAAG,CAAC,CAAC;QAE7B,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;YACrB,SAAS,EAAE,KAAK;YAChB,OAAO,EAAE,KAAK;YACd,MAAM,EAAE,EAAE;YACV,SAAS,EAAE,cAAc;YACzB,QAAQ,EAAE,cAAc;SACzB,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;QACzD,uFAAuF;QACvF,kCAAkC;QAClC,MAAM,GAAG,GAAG,sDAAsD,CAAC;QAEnE,MAAM,MAAM,GAAG,IAAA,gBAAQ,EAAC,GAAG,CAAC,CAAC;QAE7B,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;YACrB,SAAS,EAAE,YAAY;YACvB,OAAO,EAAE,KAAK;YACd,MAAM,EAAE,WAAW;YACnB,SAAS,EAAE,EAAE;YACb,QAAQ,EAAE,wBAAwB;SACnC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2DAA2D,EAAE,GAAG,EAAE;QACnE,MAAM,GAAG,GAAG,qCAAqC,CAAC;QAElD,MAAM,MAAM,GAAG,IAAA,gBAAQ,EAAC,GAAG,CAAC,CAAC;QAE7B,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;YACrB,SAAS,EAAE,QAAQ;YACnB,OAAO,EAAE,IAAI;YACb,MAAM,EAAE,EAAE;YACV,SAAS,EAAE,EAAE;YACb,QAAQ,EAAE,qBAAqB;SAChC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -15,29 +15,34 @@ const aws_1 = require("../okta/aws");
15
15
  const config_1 = require("./config");
16
16
  const idc_1 = require("./idc");
17
17
  const install_1 = require("./ssm/install");
18
- /** Maximum number of attempts to start an SSH session
19
- *
20
- * Each attempt consumes ~ 1 s.
21
- */
22
- const MAX_SSH_RETRIES = 30;
18
+ const PROPAGATION_TIMEOUT_LIMIT_MS = 30 * 1000;
23
19
  /** The name of the SessionManager port forwarding document. This document is managed by AWS. */
24
20
  const START_SSH_SESSION_DOCUMENT_NAME = "AWS-StartSSHSession";
25
- exports.awsSshProvider = {
26
- requestToSsh: (request) => {
27
- const { permission, generated } = request;
28
- const { instanceId, accountId, region } = permission.spec;
29
- const { idc, ssh, name } = generated;
30
- const { linuxUserName } = ssh;
31
- const common = { linuxUserName, accountId, region, id: instanceId };
32
- return !idc
33
- ? Object.assign(Object.assign({}, common), { role: name, type: "aws", access: "role" }) : Object.assign(Object.assign({}, common), { idc, permissionSet: name, type: "aws", access: "idc" });
21
+ /**There are 2 cases of unprovisioned access in AWS
22
+ * 1. SSM:StartSession action is missing either on the SSM document (AWS-StartSSHSession) or the EC2 instance
23
+ * 2. Temporary error when issuing an SCP command
24
+ *
25
+ * 1: results in UNAUTHORIZED_START_SESSION_MESSAGE
26
+ * 2: results in CONNECTION_CLOSED_MESSAGE
27
+ */
28
+ const unprovisionedAccessPatterns = [
29
+ /** Matches the error message that AWS SSM prints when access is not propagated */
30
+ // Note that the resource will randomly be either the SSM document or the EC2 instance
31
+ {
32
+ pattern: /An error occurred \(AccessDeniedException\) when calling the StartSession operation: User: arn:aws:sts::.*:assumed-role\/P0GrantsRole.* is not authorized to perform: ssm:StartSession on resource: arn:aws:.*:.*:.* because no identity-based policy allows the ssm:StartSession action/,
34
33
  },
35
- toCliRequest: (request) => __awaiter(void 0, void 0, void 0, function* () { return (Object.assign(Object.assign({}, request), { cliLocalData: undefined })); }),
36
- ensureInstall: () => __awaiter(void 0, void 0, void 0, function* () {
37
- if (!(yield (0, install_1.ensureSsmInstall)())) {
38
- throw "Please try again after installing the required AWS utilities";
39
- }
40
- }),
34
+ /**
35
+ * Matches the following error messages that AWS SSM pints when ssh authorized
36
+ * key access hasn't propagated to the instance yet.
37
+ * - Connection closed by UNKNOWN port 65535
38
+ * - scp: Connection closed
39
+ * - kex_exchange_identification: Connection closed by remote host
40
+ */
41
+ {
42
+ pattern: /\bConnection closed\b.*\b(?:by UNKNOWN port \d+|by remote host)?/,
43
+ },
44
+ ];
45
+ exports.awsSshProvider = {
41
46
  cloudProviderLogin: (authn, request) => __awaiter(void 0, void 0, void 0, function* () {
42
47
  var _a, _b, _c, _d;
43
48
  const { config } = yield (0, config_1.getAwsConfig)(authn, request.accountId);
@@ -50,6 +55,14 @@ exports.awsSshProvider = {
50
55
  ? yield (0, aws_1.assumeRoleWithOktaSaml)(authn, request)
51
56
  : (0, util_1.throwAssertNever)(config.login);
52
57
  }),
58
+ ensureInstall: () => __awaiter(void 0, void 0, void 0, function* () {
59
+ if (!(yield (0, install_1.ensureSsmInstall)())) {
60
+ throw "Please try again after installing the required AWS utilities";
61
+ }
62
+ }),
63
+ friendlyName: "AWS",
64
+ propagationTimeoutMs: PROPAGATION_TIMEOUT_LIMIT_MS,
65
+ preTestAccessPropagationArgs: () => undefined,
53
66
  proxyCommand: (request) => {
54
67
  return [
55
68
  "aws",
@@ -74,8 +87,17 @@ exports.awsSshProvider = {
74
87
  }
75
88
  return undefined;
76
89
  },
77
- preTestAccessPropagationArgs: () => undefined,
78
- maxRetries: MAX_SSH_RETRIES,
79
- friendlyName: "AWS",
90
+ requestToSsh: (request) => {
91
+ const { permission, generated } = request;
92
+ const { awsResourcePermission, instanceId, accountId, region } = permission.spec;
93
+ const { idcId, idcRegion } = awsResourcePermission.permission;
94
+ const { ssh, name } = generated;
95
+ const { linuxUserName } = ssh;
96
+ const common = { linuxUserName, accountId, region, id: instanceId };
97
+ return !idcId || !idcRegion
98
+ ? Object.assign(Object.assign({}, common), { role: name, type: "aws", access: "role" }) : Object.assign(Object.assign({}, common), { idc: { id: idcId, region: idcRegion }, permissionSet: name, type: "aws", access: "idc" });
99
+ },
100
+ toCliRequest: (request) => __awaiter(void 0, void 0, void 0, function* () { return (Object.assign(Object.assign({}, request), { cliLocalData: undefined })); }),
101
+ unprovisionedAccessPatterns,
80
102
  };
81
103
  //# sourceMappingURL=ssh.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ssh.js","sourceRoot":"","sources":["../../../src/plugins/aws/ssh.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ssh.js","sourceRoot":"","sources":["../../../src/plugins/aws/ssh.ts"],"names":[],"mappings":"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"}
@@ -59,6 +59,12 @@ export type AwsSshPermission = {
59
59
  accountId: string;
60
60
  region: string;
61
61
  type: "aws";
62
+ awsResourcePermission: {
63
+ permission: {
64
+ idcId?: string;
65
+ idcRegion?: string;
66
+ };
67
+ };
62
68
  };
63
69
  type: "session";
64
70
  };
@@ -67,10 +73,6 @@ export type AwsSshGenerated = {
67
73
  ssh: {
68
74
  linuxUserName: string;
69
75
  };
70
- idc?: {
71
- region: string;
72
- id: string;
73
- };
74
76
  };
75
77
  export type AwsSshPermissionSpec = PermissionSpec<"ssh", AwsSshPermission, AwsSshGenerated>;
76
78
  export type AwsSsh = CliPermissionSpec<AwsSshPermissionSpec, undefined>;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Parses out Amazon Resource Names (ARNs) from AWS into their components. Note
3
+ * that not all components are present in all ARNs (depending on the service;
4
+ * for example, S3 ARNs don't have a region or account ID), and the final
5
+ * component of the ARN (`resource`) may contain its own internal structure that
6
+ * is also service-dependent and which may also include colons. In particular,
7
+ * quoting the Amazon docs: "Be aware that the ARNs for some resources omit the
8
+ * Region, the account ID, or both the Region and the account ID."
9
+ *
10
+ * @param arn The ARN to parse as a string.
11
+ * @return A structure representing the components of the ARN. All fields will
12
+ * be defined, but some may be empty strings if they are not present in the ARN.
13
+ */
14
+ export declare const parseArn: (arn: string) => {
15
+ partition: string;
16
+ service: string;
17
+ region: string;
18
+ accountId: string;
19
+ resource: string;
20
+ };
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseArn = void 0;
4
+ /** Copyright © 2024-present P0 Security
5
+
6
+ This file is part of @p0security/cli
7
+
8
+ @p0security/cli is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 3 of the License.
9
+
10
+ @p0security/cli is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
11
+
12
+ You should have received a copy of the GNU General Public License along with @p0security/cli. If not, see <https://www.gnu.org/licenses/>.
13
+ **/
14
+ const ARN_PATTERN = /^arn:(aws|aws-us-gov|aws-cn|aws-iso|aws-iso-b):([^:]*):([^:]*):([^:]*):(.*)$/;
15
+ /**
16
+ * Parses out Amazon Resource Names (ARNs) from AWS into their components. Note
17
+ * that not all components are present in all ARNs (depending on the service;
18
+ * for example, S3 ARNs don't have a region or account ID), and the final
19
+ * component of the ARN (`resource`) may contain its own internal structure that
20
+ * is also service-dependent and which may also include colons. In particular,
21
+ * quoting the Amazon docs: "Be aware that the ARNs for some resources omit the
22
+ * Region, the account ID, or both the Region and the account ID."
23
+ *
24
+ * @param arn The ARN to parse as a string.
25
+ * @return A structure representing the components of the ARN. All fields will
26
+ * be defined, but some may be empty strings if they are not present in the ARN.
27
+ */
28
+ const parseArn = (arn) => {
29
+ // Reference: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference-arns.html
30
+ const invalidArnMsg = `Invalid AWS ARN: ${arn}`;
31
+ const match = arn.match(ARN_PATTERN);
32
+ if (!match) {
33
+ throw invalidArnMsg;
34
+ }
35
+ const [_, partition, service, region, accountId, resource] = match;
36
+ // We know these are all defined based on the regex, but TypeScript doesn't.
37
+ // Empty string is okay, so explicitly check for undefined.
38
+ if (partition === undefined ||
39
+ service === undefined ||
40
+ accountId === undefined ||
41
+ region === undefined ||
42
+ resource === undefined) {
43
+ throw invalidArnMsg;
44
+ }
45
+ return {
46
+ partition,
47
+ service,
48
+ region,
49
+ accountId,
50
+ resource,
51
+ };
52
+ };
53
+ exports.parseArn = parseArn;
54
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/plugins/aws/utils.ts"],"names":[],"mappings":";;;AAAA;;;;;;;;;GASG;AACH,MAAM,WAAW,GACf,8EAA8E,CAAC;AAEjF;;;;;;;;;;;;GAYG;AACI,MAAM,QAAQ,GAAG,CACtB,GAAW,EAOX,EAAE;IACF,kFAAkF;IAClF,MAAM,aAAa,GAAG,oBAAoB,GAAG,EAAE,CAAC;IAChD,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IAErC,IAAI,CAAC,KAAK,EAAE;QACV,MAAM,aAAa,CAAC;KACrB;IAED,MAAM,CAAC,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,CAAC,GAAG,KAAK,CAAC;IAEnE,4EAA4E;IAC5E,2DAA2D;IAC3D,IACE,SAAS,KAAK,SAAS;QACvB,OAAO,KAAK,SAAS;QACrB,SAAS,KAAK,SAAS;QACvB,MAAM,KAAK,SAAS;QACpB,QAAQ,KAAK,SAAS,EACtB;QACA,MAAM,aAAa,CAAC;KACrB;IAED,OAAO;QACL,SAAS;QACT,OAAO;QACP,MAAM;QACN,SAAS;QACT,QAAQ;KACT,CAAC;AACJ,CAAC,CAAC;AAtCW,QAAA,QAAQ,YAsCnB"}
@@ -61,7 +61,15 @@ const importSshKey = (publicKey, options) => __awaiter(void 0, void 0, void 0, f
61
61
  },
62
62
  });
63
63
  if (!response.ok) {
64
- throw `Import of SSH public key failed. HTTP error ${response.status}: ${yield response.text()}`;
64
+ if (debug) {
65
+ (0, stdio_1.print2)(`HTTP error ${response.status}: ${yield response.text()}`);
66
+ }
67
+ if (response.status === 401) {
68
+ throw `Authentication failed. Please login to Google Cloud CLI with 'gcloud auth login'`;
69
+ }
70
+ else {
71
+ throw `Import of SSH public key failed.`;
72
+ }
65
73
  }
66
74
  const data = yield response.json();
67
75
  if (debug) {
@@ -1 +1 @@
1
- {"version":3,"file":"ssh-key.js","sourceRoot":"","sources":["../../../src/plugins/google/ssh-key.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA;;;;;;;;;GASG;AACH,wDAAqD;AACrD,+CAA6C;AAG7C;;;;;;;;;;GAUG;AACI,MAAM,YAAY,GAAG,CAC1B,SAAiB,EACjB,OAA6B,EAC7B,EAAE;;IACF,MAAM,KAAK,GAAG,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,KAAK,mCAAI,KAAK,CAAC;IACtC,yDAAyD;IACzD,MAAM,WAAW,GAAG,MAAM,IAAA,uBAAU,EAAC,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE;QAC/D,MAAM;QACN,oBAAoB;KACrB,CAAC,CAAC;IAEH,MAAM,OAAO,GAAG,MAAM,IAAA,uBAAU,EAAC,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE;QACpD,QAAQ;QACR,WAAW;QACX,SAAS;KACV,CAAC,CAAC;IAEH,IAAI,KAAK,EAAE;QACT,IAAA,cAAM,EACJ,0BAA0B,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,mBAAmB,OAAO,EAAE,CAC/E,CAAC;KACH;IAED,MAAM,GAAG,GAAG,2CAA2C,OAAO,qBAAqB,CAAC;IACpF,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;QAChC,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;YACnB,GAAG,EAAE,SAAS;SACf,CAAC;QACF,OAAO,EAAE;YACP,aAAa,EAAE,UAAU,WAAW,EAAE;YACtC,cAAc,EAAE,kBAAkB;SACnC;KACF,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;QAChB,MAAM,+CAA+C,QAAQ,CAAC,MAAM,KAAK,MAAM,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC;KAClG;IAED,MAAM,IAAI,GAA+B,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;IAC/D,IAAI,KAAK,EAAE;QACT,IAAA,cAAM,EACJ,sDAAsD,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAC7E,CAAC;KACH;IAED,MAAM,EAAE,YAAY,EAAE,GAAG,IAAI,CAAC;IAE9B,yEAAyE;IACzE,MAAM,aAAa,GAAG,YAAY,CAAC,aAAa,CAAC,MAAM,CACrD,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,mBAAmB,KAAK,OAAO,CACrD,CAAC;IAEF,MAAM,YAAY,GAChB,aAAa,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC;QAChD,YAAY,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;IAEhC,IAAI,KAAK,EAAE;QACT,IAAA,cAAM,EAAC,2BAA2B,YAAY,aAAZ,YAAY,uBAAZ,YAAY,CAAE,QAAQ,EAAE,CAAC,CAAC;KAC7D;IAED,IAAI,CAAC,YAAY,EAAE;QACjB,MAAM,2HAA2H,CAAC;KACnI;IAED,OAAO,YAAY,CAAC,QAAQ,CAAC;AAC/B,CAAC,CAAA,CAAC;AAlEW,QAAA,YAAY,gBAkEvB"}
1
+ {"version":3,"file":"ssh-key.js","sourceRoot":"","sources":["../../../src/plugins/google/ssh-key.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA;;;;;;;;;GASG;AACH,wDAAqD;AACrD,+CAA6C;AAG7C;;;;;;;;;;GAUG;AACI,MAAM,YAAY,GAAG,CAC1B,SAAiB,EACjB,OAA6B,EAC7B,EAAE;;IACF,MAAM,KAAK,GAAG,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,KAAK,mCAAI,KAAK,CAAC;IACtC,yDAAyD;IACzD,MAAM,WAAW,GAAG,MAAM,IAAA,uBAAU,EAAC,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE;QAC/D,MAAM;QACN,oBAAoB;KACrB,CAAC,CAAC;IAEH,MAAM,OAAO,GAAG,MAAM,IAAA,uBAAU,EAAC,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE;QACpD,QAAQ;QACR,WAAW;QACX,SAAS;KACV,CAAC,CAAC;IAEH,IAAI,KAAK,EAAE;QACT,IAAA,cAAM,EACJ,0BAA0B,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,mBAAmB,OAAO,EAAE,CAC/E,CAAC;KACH;IAED,MAAM,GAAG,GAAG,2CAA2C,OAAO,qBAAqB,CAAC;IACpF,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;QAChC,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;YACnB,GAAG,EAAE,SAAS;SACf,CAAC;QACF,OAAO,EAAE;YACP,aAAa,EAAE,UAAU,WAAW,EAAE;YACtC,cAAc,EAAE,kBAAkB;SACnC;KACF,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;QAChB,IAAI,KAAK,EAAE;YACT,IAAA,cAAM,EAAC,cAAc,QAAQ,CAAC,MAAM,KAAK,MAAM,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;SACnE;QAED,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE;YAC3B,MAAM,kFAAkF,CAAC;SAC1F;aAAM;YACL,MAAM,kCAAkC,CAAC;SAC1C;KACF;IAED,MAAM,IAAI,GAA+B,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;IAC/D,IAAI,KAAK,EAAE;QACT,IAAA,cAAM,EACJ,sDAAsD,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAC7E,CAAC;KACH;IAED,MAAM,EAAE,YAAY,EAAE,GAAG,IAAI,CAAC;IAE9B,yEAAyE;IACzE,MAAM,aAAa,GAAG,YAAY,CAAC,aAAa,CAAC,MAAM,CACrD,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,mBAAmB,KAAK,OAAO,CACrD,CAAC;IAEF,MAAM,YAAY,GAChB,aAAa,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC;QAChD,YAAY,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;IAEhC,IAAI,KAAK,EAAE;QACT,IAAA,cAAM,EAAC,2BAA2B,YAAY,aAAZ,YAAY,uBAAZ,YAAY,CAAE,QAAQ,EAAE,CAAC,CAAC;KAC7D;IAED,IAAI,CAAC,YAAY,EAAE;QACjB,MAAM,2HAA2H,CAAC;KACnI;IAED,OAAO,YAAY,CAAC,QAAQ,CAAC;AAC/B,CAAC,CAAA,CAAC;AA1EW,QAAA,YAAY,gBA0EvB"}
@@ -23,32 +23,61 @@ You should have received a copy of the GNU General Public License along with @p0
23
23
  const ssh_1 = require("../../commands/shared/ssh");
24
24
  const install_1 = require("./install");
25
25
  const ssh_key_1 = require("./ssh-key");
26
- /** Maximum number of attempts to start an SSH session
26
+ // It typically takes < 1 minute for access to propagate on GCP, so set the time limit to 2 minutes.
27
+ const PROPAGATION_TIMEOUT_LIMIT_MS = 2 * 60 * 1000;
28
+ /**
29
+ * There are 7 cases of unprovisioned access in Google Cloud.
30
+ * These are all potentially subject to propagation delays.
31
+ * 1. The linux user name is not present in the user's Google Workspace profile `posixAccounts` attribute
32
+ * 2. The public key is not present in the user's Google Workspace profile `sshPublicKeys` attribute
33
+ * 3. The user cannot act as the service account of the compute instance
34
+ * 4. The user cannot tunnel through the IAP tunnel to the instance
35
+ * 5. The user doesn't have osLogin or osAdminLogin role to the instance
36
+ * 5.a. compute.instances.get permission is missing
37
+ * 5.b. compute.instances.osLogin permission is missing
38
+ * 6. compute.instances.osAdminLogin is not provisioned but compute.instances.osLogin is - happens when a user upgrades existing access to sudo
39
+ * 7: Rare occurrence, the exact conditions so far undetermined (together with CONNECTION_CLOSED_MESSAGE)
27
40
  *
28
- * The length of each attempt varies based on the type of error from a few seconds to < 1s
41
+ * 1, 2, 3 (yes!), 5b: result in PUBLIC_KEY_DENIED_MESSAGE
42
+ * 4: results in UNAUTHORIZED_TUNNEL_USER_MESSAGE and also CONNECTION_CLOSED_MESSAGE
43
+ * 5a: results in UNAUTHORIZED_INSTANCES_GET_MESSAGE
44
+ * 6: results in SUDO_MESSAGE
45
+ * 7: results in DESTINATION_READ_ERROR and also CONNECTION_CLOSED_MESSAGE
29
46
  */
30
- const MAX_SSH_RETRIES = 120;
31
- exports.gcpSshProvider = {
32
- requestToSsh: (request) => {
33
- return {
34
- id: request.permission.spec.instanceName,
35
- projectId: request.permission.spec.projectId,
36
- zone: request.permission.spec.zone,
37
- linuxUserName: request.cliLocalData.linuxUserName,
38
- type: "gcloud",
39
- };
47
+ const unprovisionedAccessPatterns = [
48
+ { pattern: /Permission denied \(publickey\)/ },
49
+ {
50
+ // The output of `sudo -v` when the user is not allowed to run sudo
51
+ pattern: /Sorry, user .+ may not run sudo on .+/,
40
52
  },
41
- toCliRequest: (request, options) => __awaiter(void 0, void 0, void 0, function* () {
42
- return (Object.assign(Object.assign({}, request), { cliLocalData: {
43
- linuxUserName: yield (0, ssh_key_1.importSshKey)(request.permission.spec.publicKey, options),
44
- } }));
45
- }),
53
+ { pattern: /Error while connecting \[4033: 'not authorized'\]/ },
54
+ {
55
+ pattern: /Required 'compute\.instances\.get' permission/,
56
+ validationWindowMs: 30e3,
57
+ },
58
+ { pattern: /Error while connecting \[4010: 'destination read failed'\]/ },
59
+ ];
60
+ exports.gcpSshProvider = {
61
+ // TODO support login with Google Cloud
62
+ cloudProviderLogin: () => __awaiter(void 0, void 0, void 0, function* () { return undefined; }),
46
63
  ensureInstall: () => __awaiter(void 0, void 0, void 0, function* () {
47
64
  if (!(yield (0, install_1.ensureGcpSshInstall)())) {
48
65
  throw "Please try again after installing the required GCP utilities";
49
66
  }
50
67
  }),
51
- cloudProviderLogin: () => __awaiter(void 0, void 0, void 0, function* () { return undefined; }),
68
+ friendlyName: "Google Cloud",
69
+ loginRequiredMessage: "Please login to Google Cloud CLI with 'gcloud auth login'",
70
+ loginRequiredPattern: /You do not currently have an active account selected/,
71
+ propagationTimeoutMs: PROPAGATION_TIMEOUT_LIMIT_MS,
72
+ preTestAccessPropagationArgs: (cmdArgs) => {
73
+ if ((0, ssh_1.isSudoCommand)(cmdArgs)) {
74
+ return Object.assign(Object.assign({}, cmdArgs), {
75
+ // `sudo -v` prints `Sorry, user <user> may not run sudo on <hostname>.` to stderr when user is not a sudoer.
76
+ // It prints nothing to stdout when user is a sudoer - which is important because we don't want any output from the pre-test.
77
+ command: "sudo", arguments: ["-v"] });
78
+ }
79
+ return undefined;
80
+ },
52
81
  proxyCommand: (request) => {
53
82
  return [
54
83
  "gcloud",
@@ -66,16 +95,20 @@ exports.gcpSshProvider = {
66
95
  ];
67
96
  },
68
97
  reproCommands: () => undefined,
69
- preTestAccessPropagationArgs: (cmdArgs) => {
70
- if ((0, ssh_1.isSudoCommand)(cmdArgs)) {
71
- return Object.assign(Object.assign({}, cmdArgs), {
72
- // `sudo -v` prints `Sorry, user <user> may not run sudo on <hostname>.` to stderr when user is not a sudoer.
73
- // It prints nothing to stdout when user is a sudoer - which is important because we don't want any output from the pre-test.
74
- command: "sudo", arguments: ["-v"] });
75
- }
76
- return undefined;
98
+ requestToSsh: (request) => {
99
+ return {
100
+ id: request.permission.spec.instanceName,
101
+ projectId: request.permission.spec.projectId,
102
+ zone: request.permission.spec.zone,
103
+ linuxUserName: request.cliLocalData.linuxUserName,
104
+ type: "gcloud",
105
+ };
77
106
  },
78
- maxRetries: MAX_SSH_RETRIES,
79
- friendlyName: "Google Cloud",
107
+ unprovisionedAccessPatterns,
108
+ toCliRequest: (request, options) => __awaiter(void 0, void 0, void 0, function* () {
109
+ return (Object.assign(Object.assign({}, request), { cliLocalData: {
110
+ linuxUserName: yield (0, ssh_key_1.importSshKey)(request.permission.spec.publicKey, options),
111
+ } }));
112
+ }),
80
113
  };
81
114
  //# sourceMappingURL=ssh.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ssh.js","sourceRoot":"","sources":["../../../src/plugins/google/ssh.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA;;;;;;;;;GASG;AACH,mDAA0D;AAE1D,uCAAgD;AAChD,uCAAyC;AAGzC;;;GAGG;AACH,MAAM,eAAe,GAAG,GAAG,CAAC;AAEf,QAAA,cAAc,GAIvB;IACF,YAAY,EAAE,CAAC,OAAO,EAAE,EAAE;QACxB,OAAO;YACL,EAAE,EAAE,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,YAAY;YACxC,SAAS,EAAE,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS;YAC5C,IAAI,EAAE,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI;YAClC,aAAa,EAAE,OAAO,CAAC,YAAY,CAAC,aAAa;YACjD,IAAI,EAAE,QAAQ;SACf,CAAC;IACJ,CAAC;IACD,YAAY,EAAE,CAAO,OAAO,EAAE,OAAO,EAAE,EAAE;QAAC,OAAA,iCACrC,OAAO,KACV,YAAY,EAAE;gBACZ,aAAa,EAAE,MAAM,IAAA,sBAAY,EAC/B,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,EACjC,OAAO,CACR;aACF,IACD,CAAA;MAAA;IACF,aAAa,EAAE,GAAS,EAAE;QACxB,IAAI,CAAC,CAAC,MAAM,IAAA,6BAAmB,GAAE,CAAC,EAAE;YAClC,MAAM,8DAA8D,CAAC;SACtE;IACH,CAAC,CAAA;IACD,kBAAkB,EAAE,GAAS,EAAE,kDAAC,OAAA,SAAS,CAAA,GAAA;IACzC,YAAY,EAAE,CAAC,OAAO,EAAE,EAAE;QACxB,OAAO;YACL,QAAQ;YACR,SAAS;YACT,kBAAkB;YAClB,OAAO,CAAC,EAAE;YACV,IAAI;YACJ,kEAAkE;YAClE,oGAAoG;YACpG,oEAAoE;YACpE,kDAAkD;YAClD,mBAAmB;YACnB,UAAU,OAAO,CAAC,IAAI,EAAE;YACxB,aAAa,OAAO,CAAC,SAAS,EAAE;SACjC,CAAC;IACJ,CAAC;IACD,aAAa,EAAE,GAAG,EAAE,CAAC,SAAS;IAC9B,4BAA4B,EAAE,CAAC,OAAO,EAAE,EAAE;QACxC,IAAI,IAAA,mBAAa,EAAC,OAAO,CAAC,EAAE;YAC1B,uCACK,OAAO;gBACV,6GAA6G;gBAC7G,6HAA6H;gBAC7H,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,CAAC,IAAI,CAAC,IACjB;SACH;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,UAAU,EAAE,eAAe;IAC3B,YAAY,EAAE,cAAc;CAC7B,CAAC"}
1
+ {"version":3,"file":"ssh.js","sourceRoot":"","sources":["../../../src/plugins/google/ssh.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA;;;;;;;;;GASG;AACH,mDAA0D;AAE1D,uCAAgD;AAChD,uCAAyC;AAGzC,oGAAoG;AACpG,MAAM,4BAA4B,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;AAEnD;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,2BAA2B,GAAG;IAClC,EAAE,OAAO,EAAE,iCAAiC,EAAE;IAC9C;QACE,mEAAmE;QACnE,OAAO,EAAE,uCAAuC;KACjD;IACD,EAAE,OAAO,EAAE,mDAAmD,EAAE;IAChE;QACE,OAAO,EAAE,+CAA+C;QACxD,kBAAkB,EAAE,IAAI;KACzB;IACD,EAAE,OAAO,EAAE,4DAA4D,EAAE;CACjE,CAAC;AAEE,QAAA,cAAc,GAIvB;IACF,uCAAuC;IACvC,kBAAkB,EAAE,GAAS,EAAE,kDAAC,OAAA,SAAS,CAAA,GAAA;IAEzC,aAAa,EAAE,GAAS,EAAE;QACxB,IAAI,CAAC,CAAC,MAAM,IAAA,6BAAmB,GAAE,CAAC,EAAE;YAClC,MAAM,8DAA8D,CAAC;SACtE;IACH,CAAC,CAAA;IAED,YAAY,EAAE,cAAc;IAE5B,oBAAoB,EAClB,2DAA2D;IAE7D,oBAAoB,EAAE,sDAAsD;IAE5E,oBAAoB,EAAE,4BAA4B;IAElD,4BAA4B,EAAE,CAAC,OAAO,EAAE,EAAE;QACxC,IAAI,IAAA,mBAAa,EAAC,OAAO,CAAC,EAAE;YAC1B,uCACK,OAAO;gBACV,6GAA6G;gBAC7G,6HAA6H;gBAC7H,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,CAAC,IAAI,CAAC,IACjB;SACH;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,YAAY,EAAE,CAAC,OAAO,EAAE,EAAE;QACxB,OAAO;YACL,QAAQ;YACR,SAAS;YACT,kBAAkB;YAClB,OAAO,CAAC,EAAE;YACV,IAAI;YACJ,kEAAkE;YAClE,oGAAoG;YACpG,oEAAoE;YACpE,kDAAkD;YAClD,mBAAmB;YACnB,UAAU,OAAO,CAAC,IAAI,EAAE;YACxB,aAAa,OAAO,CAAC,SAAS,EAAE;SACjC,CAAC;IACJ,CAAC;IAED,aAAa,EAAE,GAAG,EAAE,CAAC,SAAS;IAE9B,YAAY,EAAE,CAAC,OAAO,EAAE,EAAE;QACxB,OAAO;YACL,EAAE,EAAE,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,YAAY;YACxC,SAAS,EAAE,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS;YAC5C,IAAI,EAAE,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI;YAClC,aAAa,EAAE,OAAO,CAAC,YAAY,CAAC,aAAa;YACjD,IAAI,EAAE,QAAQ;SACf,CAAC;IACJ,CAAC;IAED,2BAA2B;IAE3B,YAAY,EAAE,CAAO,OAAO,EAAE,OAAO,EAAE,EAAE;QAAC,OAAA,iCACrC,OAAO,KACV,YAAY,EAAE;gBACZ,aAAa,EAAE,MAAM,IAAA,sBAAY,EAC/B,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,EACjC,OAAO,CACR;aACF,IACD,CAAA;MAAA;CACH,CAAC"}
@@ -12,7 +12,7 @@ import { KubeconfigCommandArgs } from "../../commands/kubeconfig";
12
12
  import { Authn } from "../../types/identity";
13
13
  import { Request } from "../../types/request";
14
14
  import { AwsCredentials } from "../aws/types";
15
- import { K8sGenerated, K8sPermissionSpec } from "./types";
15
+ import { K8sPermissionSpec } from "./types";
16
16
  import yargs from "yargs";
17
17
  export declare const getAndValidateK8sIntegration: (authn: Authn, clusterId: string) => Promise<{
18
18
  clusterConfig: {
@@ -24,4 +24,4 @@ export declare const getAndValidateK8sIntegration: (authn: Authn, clusterId: str
24
24
  }>;
25
25
  export declare const requestAccessToCluster: (authn: Authn, args: yargs.ArgumentsCamelCase<KubeconfigCommandArgs>, clusterId: string, role: string) => Promise<Request<K8sPermissionSpec>>;
26
26
  export declare const profileName: (eksCluterName: string) => string;
27
- export declare const awsCloudAuth: (authn: Authn, awsAccountId: string, generated: K8sGenerated, loginType: "federated" | "idc") => Promise<AwsCredentials>;
27
+ export declare const awsCloudAuth: (authn: Authn, awsAccountId: string, request: Request<K8sPermissionSpec>, loginType: "federated" | "idc") => Promise<AwsCredentials>;
@@ -17,6 +17,7 @@ const stdio_1 = require("../../drivers/stdio");
17
17
  const util_1 = require("../../util");
18
18
  const config_1 = require("../aws/config");
19
19
  const idc_1 = require("../aws/idc");
20
+ const utils_1 = require("../aws/utils");
20
21
  const aws_1 = require("../okta/aws");
21
22
  const firestore_2 = require("firebase/firestore");
22
23
  const lodash_1 = require("lodash");
@@ -28,15 +29,16 @@ const getAndValidateK8sIntegration = (authn, clusterId) => __awaiter(void 0, voi
28
29
  if (!config) {
29
30
  throw `Cluster with ID ${clusterId} not found`;
30
31
  }
31
- if (config.state !== "installed" || config.provider.type !== "aws") {
32
+ if (config.state !== "installed") {
32
33
  throw `Cluster with ID ${clusterId} is not installed`;
33
34
  }
34
- const { provider } = config;
35
- const { accountId: awsAccountId, clusterArn: awsClusterArn } = provider;
36
- if (!awsAccountId || !awsClusterArn) {
35
+ const { hosting } = config;
36
+ if (hosting.type !== "aws") {
37
37
  throw (`This command currently only supports AWS EKS clusters, and ${clusterId} is not configured as one.\n` +
38
38
  "You can request access to the cluster using the `p0 request k8s` command.");
39
39
  }
40
+ const { arn: awsClusterArn } = hosting;
41
+ const { accountId: awsAccountId } = (0, utils_1.parseArn)(awsClusterArn);
40
42
  const { config: awsConfig } = yield (0, config_1.getAwsConfig)(authn, awsAccountId);
41
43
  const { login: awsLogin } = awsConfig;
42
44
  // Verify that the AWS auth type is supported before issuing the requests
@@ -70,28 +72,29 @@ const requestAccessToCluster = (authn, args, clusterId, role) => __awaiter(void
70
72
  if (!response) {
71
73
  throw "Did not receive access ID from server";
72
74
  }
73
- const { id, isPreexisting } = response;
74
- if (!isPreexisting) {
75
- (0, stdio_1.print2)("Waiting for access to be provisioned. This may take up to a minute.");
76
- }
77
- return yield (0, shared_1.waitForProvisioning)(authn, id);
75
+ const { id } = response;
76
+ return yield (0, stdio_1.spinUntil)("Waiting for access to be provisioned. This may take up to a minute.", (0, shared_1.waitForProvisioning)(authn, id));
78
77
  });
79
78
  exports.requestAccessToCluster = requestAccessToCluster;
80
79
  const profileName = (eksCluterName) => `p0cli-managed-eks-${eksCluterName}`;
81
80
  exports.profileName = profileName;
82
- const awsCloudAuth = (authn, awsAccountId, generated, loginType) => __awaiter(void 0, void 0, void 0, function* () {
81
+ const awsCloudAuth = (authn, awsAccountId, request, loginType) => __awaiter(void 0, void 0, void 0, function* () {
82
+ var _c;
83
+ const { permission, generated } = request;
83
84
  const { eksGenerated } = generated;
84
- const { name, idc } = eksGenerated;
85
+ const { name } = eksGenerated;
85
86
  switch (loginType) {
86
- case "idc":
87
- if (!idc) {
87
+ case "idc": {
88
+ const { idcId, idcRegion } = (_c = permission.awsResourcePermission) !== null && _c !== void 0 ? _c : {};
89
+ if (!idcId || !idcRegion) {
88
90
  throw "AWS is configured to use Identity Center, but IDC information wasn't received in the request.";
89
91
  }
90
92
  return yield (0, idc_1.assumeRoleWithIdc)({
91
93
  accountId: awsAccountId,
92
94
  permissionSet: name,
93
- idc,
95
+ idc: { id: idcId, region: idcRegion },
94
96
  });
97
+ }
95
98
  case "federated":
96
99
  return yield (0, aws_1.assumeRoleWithOktaSaml)(authn, {
97
100
  accountId: awsAccountId,