@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.
- package/dist/commands/__tests__/login.test.js +17 -0
- package/dist/commands/__tests__/login.test.js.map +1 -1
- package/dist/commands/__tests__/ls.test.js +4 -3
- package/dist/commands/__tests__/ls.test.js.map +1 -1
- package/dist/commands/__tests__/ssh.test.js +10 -5
- package/dist/commands/__tests__/ssh.test.js.map +1 -1
- package/dist/commands/kubeconfig.js +11 -15
- package/dist/commands/kubeconfig.js.map +1 -1
- package/dist/commands/login.js +11 -0
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/ls.js +4 -6
- package/dist/commands/ls.js.map +1 -1
- package/dist/commands/shared/request.js +2 -2
- package/dist/commands/shared/request.js.map +1 -1
- package/dist/drivers/__mocks__/stdio.d.ts +14 -0
- package/dist/drivers/__mocks__/stdio.js +26 -0
- package/dist/drivers/__mocks__/stdio.js.map +1 -0
- package/dist/drivers/ansi.d.ts +8 -0
- package/dist/drivers/ansi.js +25 -0
- package/dist/drivers/ansi.js.map +1 -0
- package/dist/drivers/auth.d.ts +1 -0
- package/dist/drivers/auth.js +8 -4
- package/dist/drivers/auth.js.map +1 -1
- package/dist/drivers/stdio.d.ts +6 -5
- package/dist/drivers/stdio.js +50 -7
- package/dist/drivers/stdio.js.map +1 -1
- package/dist/plugins/aws/__tests__/utils.test.d.ts +1 -0
- package/dist/plugins/aws/__tests__/utils.test.js +82 -0
- package/dist/plugins/aws/__tests__/utils.test.js.map +1 -0
- package/dist/plugins/aws/ssh.js +45 -23
- package/dist/plugins/aws/ssh.js.map +1 -1
- package/dist/plugins/aws/types.d.ts +6 -4
- package/dist/plugins/aws/utils.d.ts +20 -0
- package/dist/plugins/aws/utils.js +54 -0
- package/dist/plugins/aws/utils.js.map +1 -0
- package/dist/plugins/google/ssh-key.js +9 -1
- package/dist/plugins/google/ssh-key.js.map +1 -1
- package/dist/plugins/google/ssh.js +61 -28
- package/dist/plugins/google/ssh.js.map +1 -1
- package/dist/plugins/kubeconfig/index.d.ts +2 -2
- package/dist/plugins/kubeconfig/index.js +17 -14
- package/dist/plugins/kubeconfig/index.js.map +1 -1
- package/dist/plugins/kubeconfig/types.d.ts +9 -8
- package/dist/plugins/ssh/index.js +55 -86
- package/dist/plugins/ssh/index.js.map +1 -1
- package/dist/types/ssh.d.ts +28 -13
- package/package.json +3 -3
package/dist/drivers/stdio.js
CHANGED
|
@@ -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.
|
|
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
|
|
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
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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
|
-
|
|
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
|
|
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"}
|
package/dist/plugins/aws/ssh.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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
|
-
|
|
78
|
-
|
|
79
|
-
|
|
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":";;;;;;;;;;;;AAWA,qCAA8C;AAC9C,qCAAqD;AACrD,qCAAwC;AACxC,+BAA0C;AAC1C,2CAAiD;AASjD
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
-
*
|
|
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
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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
|
-
|
|
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
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
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
|
-
|
|
79
|
-
|
|
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
|
|
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 {
|
|
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,
|
|
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"
|
|
32
|
+
if (config.state !== "installed") {
|
|
32
33
|
throw `Cluster with ID ${clusterId} is not installed`;
|
|
33
34
|
}
|
|
34
|
-
const {
|
|
35
|
-
|
|
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
|
|
74
|
-
|
|
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,
|
|
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
|
|
85
|
+
const { name } = eksGenerated;
|
|
85
86
|
switch (loginType) {
|
|
86
|
-
case "idc":
|
|
87
|
-
|
|
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,
|