@p0security/cli 0.4.2 → 0.5.0
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__/ssh.test.js +1 -1
- package/dist/commands/aws/__tests__/role.test.js +12 -8
- package/dist/commands/aws/role.d.ts +5 -3
- package/dist/commands/aws/role.js +10 -9
- package/dist/plugins/aws/config.d.ts +6 -1
- package/dist/plugins/aws/config.js +10 -4
- package/dist/plugins/aws/types.d.ts +29 -20
- package/dist/plugins/okta/aws.js +1 -1
- package/dist/plugins/okta/login.d.ts +2 -2
- package/dist/plugins/okta/login.js +1 -1
- package/package.json +1 -1
|
@@ -53,29 +53,33 @@ beforeEach(() => {
|
|
|
53
53
|
describe("aws role", () => {
|
|
54
54
|
describe("a single installed account", () => {
|
|
55
55
|
const item = {
|
|
56
|
-
|
|
57
|
-
id: "1",
|
|
58
|
-
description: "1 (test)",
|
|
59
|
-
},
|
|
56
|
+
label: "test",
|
|
60
57
|
state: "installed",
|
|
61
58
|
};
|
|
62
59
|
describe("without Okta SAML", () => {
|
|
63
|
-
(0, firestore_1.mockGetDoc)({
|
|
60
|
+
(0, firestore_1.mockGetDoc)({ "iam-write": { "1": item } });
|
|
64
61
|
describe.each([
|
|
65
62
|
["ls", "aws role ls"],
|
|
66
63
|
["assume", "aws role assume Role1"],
|
|
67
64
|
])("%s", (_, command) => {
|
|
68
65
|
it("should print a friendly error message", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
69
66
|
const error = yield (0, yargs_1.failure)((0, __1.awsCommand)((0, yargs_2.default)()), command);
|
|
70
|
-
expect(error).toMatchInlineSnapshot(`"Account
|
|
67
|
+
expect(error).toMatchInlineSnapshot(`"Account test is not configured for Okta SAML login."`);
|
|
71
68
|
}));
|
|
72
69
|
});
|
|
73
70
|
});
|
|
74
71
|
describe("with Okta SAML", () => {
|
|
75
72
|
beforeEach(() => {
|
|
76
73
|
(0, firestore_1.mockGetDoc)({
|
|
77
|
-
|
|
78
|
-
|
|
74
|
+
"iam-write": {
|
|
75
|
+
"1": Object.assign(Object.assign({}, item), { login: {
|
|
76
|
+
type: "federated",
|
|
77
|
+
provider: {
|
|
78
|
+
type: "okta",
|
|
79
|
+
appId: "0oabcdefgh",
|
|
80
|
+
identityProvider: "okta",
|
|
81
|
+
},
|
|
82
|
+
} }),
|
|
79
83
|
},
|
|
80
84
|
});
|
|
81
85
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { AwsFederatedLogin } from "../../plugins/aws/types";
|
|
2
2
|
import { Authn } from "../../types/identity";
|
|
3
3
|
import yargs from "yargs";
|
|
4
4
|
export declare const role: (yargs: yargs.Argv<{
|
|
@@ -15,8 +15,10 @@ export declare const role: (yargs: yargs.Argv<{
|
|
|
15
15
|
*/
|
|
16
16
|
export declare const initOktaSaml: (authn: Authn, account: string | undefined) => Promise<{
|
|
17
17
|
samlResponse: string;
|
|
18
|
-
config:
|
|
19
|
-
|
|
18
|
+
config: {
|
|
19
|
+
id: string;
|
|
20
|
+
} & import("../../plugins/aws/types").AwsItemConfig & {
|
|
21
|
+
login: AwsFederatedLogin;
|
|
20
22
|
};
|
|
21
23
|
account: string;
|
|
22
24
|
}>;
|
|
@@ -42,21 +42,22 @@ const role = (yargs) => yargs.command("role", "Interact with AWS roles", (yargs)
|
|
|
42
42
|
(0, firestore_1.guard)(oktaAwsAssumeRole))
|
|
43
43
|
.demandCommand(1));
|
|
44
44
|
exports.role = role;
|
|
45
|
-
const
|
|
45
|
+
const isFederatedLogin = (config) => { var _a; return ((_a = config.login) === null || _a === void 0 ? void 0 : _a.type) === "federated"; };
|
|
46
46
|
/** Retrieves the configured Okta SAML response for the specified account
|
|
47
47
|
*
|
|
48
48
|
* If no account is passed, and the organization only has one account configured,
|
|
49
49
|
* assumes that account.
|
|
50
50
|
*/
|
|
51
51
|
const initOktaSaml = (authn, account) => __awaiter(void 0, void 0, void 0, function* () {
|
|
52
|
+
var _a;
|
|
52
53
|
const { identity, config } = yield (0, config_1.getAwsConfig)(authn, account);
|
|
53
|
-
if (!
|
|
54
|
-
throw `Account ${config.
|
|
55
|
-
const samlResponse = yield (0, login_1.getSamlResponse)(identity, config.
|
|
54
|
+
if (!isFederatedLogin(config))
|
|
55
|
+
throw `Account ${(_a = config.label) !== null && _a !== void 0 ? _a : config.id} is not configured for Okta SAML login.`;
|
|
56
|
+
const samlResponse = yield (0, login_1.getSamlResponse)(identity, config.login);
|
|
56
57
|
return {
|
|
57
58
|
samlResponse,
|
|
58
59
|
config,
|
|
59
|
-
account: config.
|
|
60
|
+
account: config.id,
|
|
60
61
|
};
|
|
61
62
|
});
|
|
62
63
|
exports.initOktaSaml = initOktaSaml;
|
|
@@ -88,10 +89,10 @@ exports.rolesFromSaml = rolesFromSaml;
|
|
|
88
89
|
* - The requested role is assigned to the user in Okta
|
|
89
90
|
*/
|
|
90
91
|
const oktaAwsAssumeRole = (args) => __awaiter(void 0, void 0, void 0, function* () {
|
|
91
|
-
var
|
|
92
|
+
var _b;
|
|
92
93
|
const authn = yield (0, auth_1.authenticate)();
|
|
93
94
|
const awsCredential = yield (0, aws_1.assumeRoleWithOktaSaml)(authn, args);
|
|
94
|
-
const isTty = (
|
|
95
|
+
const isTty = (_b = typescript_1.sys.writeOutputIsTTY) === null || _b === void 0 ? void 0 : _b.call(typescript_1.sys);
|
|
95
96
|
if (isTty)
|
|
96
97
|
(0, stdio_1.print2)("Execute the following commands:\n");
|
|
97
98
|
const indent = isTty ? " " : "";
|
|
@@ -107,11 +108,11 @@ Or, populate these environment variables using BASH command substitution:
|
|
|
107
108
|
});
|
|
108
109
|
/** Lists assigned AWS roles for this user on this account */
|
|
109
110
|
const oktaAwsListRoles = (args) => __awaiter(void 0, void 0, void 0, function* () {
|
|
110
|
-
var
|
|
111
|
+
var _c;
|
|
111
112
|
const authn = yield (0, auth_1.authenticate)();
|
|
112
113
|
const { account, samlResponse } = yield (0, exports.initOktaSaml)(authn, args.account);
|
|
113
114
|
const { arns, roles } = (0, exports.rolesFromSaml)(account, samlResponse);
|
|
114
|
-
const isTty = (
|
|
115
|
+
const isTty = (_c = typescript_1.sys.writeOutputIsTTY) === null || _c === void 0 ? void 0 : _c.call(typescript_1.sys);
|
|
115
116
|
if (isTty)
|
|
116
117
|
(0, stdio_1.print2)(`Your available roles for account ${account}:`);
|
|
117
118
|
if (!(roles === null || roles === void 0 ? void 0 : roles.length)) {
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { Authn } from "../../types/identity";
|
|
2
2
|
export declare const getAwsConfig: (authn: Authn, account: string | undefined) => Promise<{
|
|
3
3
|
identity: import("../../types/identity").Identity;
|
|
4
|
-
config:
|
|
4
|
+
config: {
|
|
5
|
+
label?: string | undefined;
|
|
6
|
+
state: string;
|
|
7
|
+
login?: (import("./types").AwsIamLogin | import("./types").AwsIdcLogin | import("./types").AwsFederatedLogin) | undefined;
|
|
8
|
+
id: string;
|
|
9
|
+
};
|
|
5
10
|
}>;
|
|
@@ -22,17 +22,23 @@ You should have received a copy of the GNU General Public License along with @p0
|
|
|
22
22
|
**/
|
|
23
23
|
const firestore_1 = require("../../drivers/firestore");
|
|
24
24
|
const firestore_2 = require("firebase/firestore");
|
|
25
|
+
const lodash_1 = require("lodash");
|
|
25
26
|
const getAwsConfig = (authn, account) => __awaiter(void 0, void 0, void 0, function* () {
|
|
26
|
-
var _a
|
|
27
|
+
var _a;
|
|
27
28
|
const { identity } = authn;
|
|
28
29
|
const snapshot = yield (0, firestore_2.getDoc)((0, firestore_1.doc)(`o/${identity.org.tenantId}/integrations/aws`));
|
|
29
30
|
const config = snapshot.data();
|
|
30
31
|
// TODO: Support alias lookup
|
|
32
|
+
const allItems = (0, lodash_1.sortBy)(Object.entries((_a = config === null || config === void 0 ? void 0 : config["iam-write"]) !== null && _a !== void 0 ? _a : {}).filter(([, { state }]) => state === "installed"), ([id]) => id);
|
|
31
33
|
const item = account
|
|
32
|
-
? (
|
|
33
|
-
:
|
|
34
|
+
? allItems.find(([id, { label }]) => id === account || label === account)
|
|
35
|
+
: allItems.length !== 1
|
|
36
|
+
? (() => {
|
|
37
|
+
throw `Please select a unique AWS account with --account; valid accounts are:\n${allItems.map(([id, { label }]) => label !== null && label !== void 0 ? label : id).join("\n")}`;
|
|
38
|
+
})()
|
|
39
|
+
: allItems[0];
|
|
34
40
|
if (!item)
|
|
35
41
|
throw `P0 is not installed on AWS account ${account}`;
|
|
36
|
-
return { identity, config: item };
|
|
42
|
+
return { identity, config: Object.assign({ id: item[0] }, item[1]) };
|
|
37
43
|
});
|
|
38
44
|
exports.getAwsConfig = getAwsConfig;
|
|
@@ -13,32 +13,41 @@ export declare type AwsCredentials = {
|
|
|
13
13
|
AWS_SECRET_ACCESS_KEY: string;
|
|
14
14
|
AWS_SESSION_TOKEN: string;
|
|
15
15
|
};
|
|
16
|
-
export declare type
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
export declare type AwsIamLogin = {
|
|
17
|
+
type: "iam";
|
|
18
|
+
identity: {
|
|
19
|
+
type: "email";
|
|
20
|
+
} | {
|
|
21
|
+
type: "tag";
|
|
22
|
+
tagName: string;
|
|
23
|
+
};
|
|
20
24
|
};
|
|
21
|
-
declare type
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
} | {
|
|
25
|
-
id: "user_tag";
|
|
26
|
-
tagName: string;
|
|
27
|
-
} | {
|
|
28
|
-
id: "username";
|
|
25
|
+
export declare type AwsIdcLogin = {
|
|
26
|
+
type: "idc";
|
|
27
|
+
parent: string;
|
|
29
28
|
};
|
|
30
|
-
export declare type
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
29
|
+
export declare type AwsFederatedLogin = {
|
|
30
|
+
type: "federated";
|
|
31
|
+
provider: {
|
|
32
|
+
type: "okta";
|
|
33
|
+
appId: string;
|
|
34
|
+
identityProvider: string;
|
|
35
|
+
method: {
|
|
36
|
+
type: "saml";
|
|
37
|
+
};
|
|
34
38
|
};
|
|
39
|
+
};
|
|
40
|
+
declare type AwsLogin = AwsFederatedLogin | AwsIamLogin | AwsIdcLogin;
|
|
41
|
+
export declare type AwsItemConfig = {
|
|
42
|
+
label?: string;
|
|
35
43
|
state: string;
|
|
36
|
-
|
|
44
|
+
login?: AwsLogin;
|
|
37
45
|
};
|
|
46
|
+
export declare type AwsItem = {
|
|
47
|
+
id: string;
|
|
48
|
+
} & AwsItemConfig;
|
|
38
49
|
export declare type AwsConfig = {
|
|
39
|
-
|
|
40
|
-
items: AwsItemConfig[];
|
|
41
|
-
};
|
|
50
|
+
"iam-write": Record<string, AwsItemConfig>;
|
|
42
51
|
};
|
|
43
52
|
export declare type AwsSsh = {
|
|
44
53
|
permission: {
|
package/dist/plugins/okta/aws.js
CHANGED
|
@@ -33,7 +33,7 @@ const assumeRoleWithOktaSaml = (authn, args) => __awaiter(void 0, void 0, void 0
|
|
|
33
33
|
account,
|
|
34
34
|
role: args.role,
|
|
35
35
|
saml: {
|
|
36
|
-
providerName: config.
|
|
36
|
+
providerName: config.login.provider.identityProvider,
|
|
37
37
|
response: samlResponse,
|
|
38
38
|
},
|
|
39
39
|
});
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Identity } from "../../types/identity";
|
|
2
2
|
import { TokenResponse } from "../../types/oidc";
|
|
3
3
|
import { OrgData } from "../../types/org";
|
|
4
|
-
import {
|
|
4
|
+
import { AwsFederatedLogin } from "../aws/types";
|
|
5
5
|
/** Logs in to Okta via OIDC */
|
|
6
6
|
export declare const oktaLogin: (org: OrgData) => Promise<TokenResponse>;
|
|
7
7
|
/** Retrieves a SAML response for an okta app */
|
|
8
|
-
export declare const getSamlResponse: (identity: Identity, config:
|
|
8
|
+
export declare const getSamlResponse: (identity: Identity, config: AwsFederatedLogin) => Promise<string>;
|
|
@@ -155,7 +155,7 @@ exports.oktaLogin = oktaLogin;
|
|
|
155
155
|
/** Retrieves a SAML response for an okta app */
|
|
156
156
|
// TODO: Inject Okta app
|
|
157
157
|
const getSamlResponse = (identity, config) => __awaiter(void 0, void 0, void 0, function* () {
|
|
158
|
-
const webTokenResponse = yield fetchSsoWebToken(config.appId, identity);
|
|
158
|
+
const webTokenResponse = yield fetchSsoWebToken(config.provider.appId, identity);
|
|
159
159
|
const samlResponse = yield fetchSamlResponse(identity.org, webTokenResponse);
|
|
160
160
|
if (!samlResponse) {
|
|
161
161
|
throw "No SAML assertion obtained from Okta.";
|