@p0security/cli 0.8.0 → 0.8.2
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 +11 -10
- package/dist/commands/scp.d.ts +1 -1
- package/dist/commands/scp.js +11 -5
- package/dist/commands/shared/index.d.ts +4 -0
- package/dist/commands/shared/index.js +67 -0
- package/dist/commands/{shared.d.ts → shared/ssh.d.ts} +7 -14
- package/dist/commands/{shared.js → shared/ssh.js} +30 -64
- package/dist/commands/ssh.d.ts +1 -1
- package/dist/commands/ssh.js +10 -4
- package/dist/common/retry.d.ts +9 -0
- package/dist/common/retry.js +50 -0
- package/dist/common/subprocess.d.ts +10 -0
- package/dist/common/subprocess.js +72 -0
- package/dist/drivers/auth.d.ts +1 -1
- package/dist/drivers/auth.js +7 -3
- package/dist/plugins/aws/config.d.ts +1 -1
- package/dist/plugins/aws/idc/index.d.ts +16 -0
- package/dist/plugins/aws/idc/index.js +150 -0
- package/dist/plugins/aws/ssh.d.ts +13 -0
- package/dist/plugins/aws/ssh.js +24 -0
- package/dist/plugins/aws/types.d.ts +42 -16
- package/dist/plugins/google/ssh-key.d.ts +14 -0
- package/dist/plugins/google/ssh-key.js +80 -0
- package/dist/plugins/google/ssh.d.ts +15 -0
- package/dist/plugins/google/ssh.js +29 -0
- package/dist/plugins/google/types.d.ts +57 -0
- package/dist/plugins/google/types.js +2 -0
- package/dist/plugins/login.d.ts +3 -0
- package/dist/plugins/login.js +10 -0
- package/dist/plugins/oidc/login.d.ts +33 -2
- package/dist/plugins/oidc/login.js +100 -60
- package/dist/plugins/okta/aws.d.ts +1 -1
- package/dist/plugins/okta/aws.js +2 -2
- package/dist/plugins/okta/login.js +11 -1
- package/dist/plugins/ping/login.d.ts +2 -1
- package/dist/plugins/ping/login.js +11 -1
- package/dist/plugins/{aws/ssm → ssh}/index.d.ts +3 -2
- package/dist/plugins/ssh/index.js +311 -0
- package/dist/plugins/ssh/types.d.ts +4 -0
- package/dist/plugins/ssh-agent/index.js +5 -39
- package/dist/types/aws/oidc.d.ts +36 -0
- package/dist/types/aws/oidc.js +12 -0
- package/dist/types/oidc.d.ts +21 -0
- package/dist/types/request.d.ts +9 -11
- package/dist/types/request.js +0 -10
- package/dist/types/ssh.d.ts +27 -0
- package/dist/types/ssh.js +5 -0
- package/package.json +1 -1
- package/dist/plugins/aws/ssm/index.js +0 -213
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.assumeRoleWithIdc = exports.registerClient = void 0;
|
|
13
|
+
/** Copyright © 2024-present P0 Security
|
|
14
|
+
|
|
15
|
+
This file is part of @p0security/cli
|
|
16
|
+
|
|
17
|
+
@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.
|
|
18
|
+
|
|
19
|
+
@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.
|
|
20
|
+
|
|
21
|
+
You should have received a copy of the GNU General Public License along with @p0security/cli. If not, see <https://www.gnu.org/licenses/>.
|
|
22
|
+
**/
|
|
23
|
+
const fetch_1 = require("../../../common/fetch");
|
|
24
|
+
const retry_1 = require("../../../common/retry");
|
|
25
|
+
const auth_1 = require("../../../drivers/auth");
|
|
26
|
+
const login_1 = require("../../oidc/login");
|
|
27
|
+
const HOURS = 60 * 60 * 1000;
|
|
28
|
+
const DAYS = 24 * HOURS;
|
|
29
|
+
const AWS_TOKEN_EXPIRY = 1 * HOURS;
|
|
30
|
+
const AWS_CLIENT_TOKEN_EXPIRY = 90 * DAYS; // the token has lifetime of 90 days
|
|
31
|
+
const AWS_SSO_SCOPES = ["sso:account:access"];
|
|
32
|
+
const registerClient = (region) => __awaiter(void 0, void 0, void 0, function* () {
|
|
33
|
+
return yield (0, auth_1.cached)("aws-idc-client", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
34
|
+
const init = {
|
|
35
|
+
method: "POST",
|
|
36
|
+
body: JSON.stringify({
|
|
37
|
+
clientName: "p0Cli",
|
|
38
|
+
clientType: "public",
|
|
39
|
+
grantTypes: [login_1.DEVICE_GRANT_TYPE],
|
|
40
|
+
scopes: AWS_SSO_SCOPES,
|
|
41
|
+
}),
|
|
42
|
+
};
|
|
43
|
+
const response = yield fetch(`https://oidc.${region}.amazonaws.com/client/register`, init);
|
|
44
|
+
return yield response.json();
|
|
45
|
+
}), { duration: AWS_CLIENT_TOKEN_EXPIRY }, (data) => data.clientSecretExpiresAt
|
|
46
|
+
? data.clientSecretExpiresAt < Date.now()
|
|
47
|
+
: true);
|
|
48
|
+
});
|
|
49
|
+
exports.registerClient = registerClient;
|
|
50
|
+
const awsIdcHelpers = (clientCredentials, idc) => {
|
|
51
|
+
const { clientId, clientSecret } = clientCredentials;
|
|
52
|
+
const { id, region } = idc;
|
|
53
|
+
const buildOidcAuthorizeRequest = () => ({
|
|
54
|
+
init: {
|
|
55
|
+
method: "POST",
|
|
56
|
+
body: JSON.stringify({
|
|
57
|
+
clientId,
|
|
58
|
+
clientSecret,
|
|
59
|
+
startUrl: `https://${id}.awsapps.com/start`,
|
|
60
|
+
}),
|
|
61
|
+
},
|
|
62
|
+
url: `https://oidc.${region}.amazonaws.com/device_authorization`,
|
|
63
|
+
});
|
|
64
|
+
const buildIdcTokenRequest = (authorizeResponse) => ({
|
|
65
|
+
url: `https://oidc.${region}.amazonaws.com/token`,
|
|
66
|
+
init: {
|
|
67
|
+
method: "POST",
|
|
68
|
+
body: JSON.stringify({
|
|
69
|
+
clientId,
|
|
70
|
+
clientSecret,
|
|
71
|
+
deviceCode: authorizeResponse.deviceCode,
|
|
72
|
+
grantType: login_1.DEVICE_GRANT_TYPE,
|
|
73
|
+
}),
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
/**
|
|
77
|
+
* Exchanges the oidc token for AWS credentials for a given account and permission set
|
|
78
|
+
* @param oidcResponse oidc token response fot he oidc /token endpoint
|
|
79
|
+
* @param request accountId and permissionSet to exchange for AWS credentials
|
|
80
|
+
* @returns
|
|
81
|
+
*/
|
|
82
|
+
const exchangeForAwsCredentials = (oidcResponse, request) => __awaiter(void 0, void 0, void 0, function* () {
|
|
83
|
+
// There is a delay in between aws issuing the sso token and it being available for exchange for AWS credentials
|
|
84
|
+
// When exchanging token immediately, an "unauthorized" may will be thrown, so retry with sleep.
|
|
85
|
+
return yield (0, retry_1.retryWithSleep)(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
86
|
+
const init = {
|
|
87
|
+
method: "GET",
|
|
88
|
+
headers: {
|
|
89
|
+
"x-amz-sso_bearer_token": oidcResponse.accessToken,
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
const { accountId, permissionSet } = request;
|
|
93
|
+
if (accountId === undefined)
|
|
94
|
+
throw new Error("Could not find an AWS account ID for this access request");
|
|
95
|
+
const params = new URLSearchParams();
|
|
96
|
+
params.append("account_id", accountId);
|
|
97
|
+
params.append("role_name", permissionSet);
|
|
98
|
+
const response = yield fetch(`https://portal.sso.${region}.amazonaws.com/federation/credentials?${params.toString()}`, init);
|
|
99
|
+
if (!response.ok)
|
|
100
|
+
throw new Error(`Failed to fetch AWS credentials: ${response.statusText}: ${yield response.text()}`);
|
|
101
|
+
return yield response.json();
|
|
102
|
+
}), () => true, 3);
|
|
103
|
+
});
|
|
104
|
+
return {
|
|
105
|
+
loginSteps: {
|
|
106
|
+
providerType: "aws-oidc",
|
|
107
|
+
validateResponse: fetch_1.validateResponse,
|
|
108
|
+
buildAuthorizeRequest: buildOidcAuthorizeRequest,
|
|
109
|
+
buildTokenRequest: buildIdcTokenRequest,
|
|
110
|
+
processAuthzExpiry: (authorize) => ({
|
|
111
|
+
expires_in: authorize.expiresIn,
|
|
112
|
+
interval: authorize.interval,
|
|
113
|
+
}),
|
|
114
|
+
processAuthzResponse: (authorize) => ({
|
|
115
|
+
user_code: authorize.userCode,
|
|
116
|
+
verification_uri_complete: authorize.verificationUriComplete,
|
|
117
|
+
}),
|
|
118
|
+
},
|
|
119
|
+
exchangeForAwsCredentials,
|
|
120
|
+
};
|
|
121
|
+
};
|
|
122
|
+
/**
|
|
123
|
+
* Returns AWS credentials for the specified account and permission set for the authorized user
|
|
124
|
+
* @param args accountId, permissionSet and idc to assume role associated with the permission set
|
|
125
|
+
* @returns
|
|
126
|
+
*/
|
|
127
|
+
const assumeRoleWithIdc = (args) => __awaiter(void 0, void 0, void 0, function* () {
|
|
128
|
+
return yield (0, auth_1.cached)(`aws-idc-${args.accountId}-${args.permissionSet}`, () => __awaiter(void 0, void 0, void 0, function* () {
|
|
129
|
+
const { idc } = args;
|
|
130
|
+
const { region } = idc;
|
|
131
|
+
const clientSecrets = yield (0, exports.registerClient)(region);
|
|
132
|
+
const { loginSteps, exchangeForAwsCredentials } = awsIdcHelpers(clientSecrets, idc);
|
|
133
|
+
const oidcResponse = yield (0, auth_1.cached)("aws-idc-device-authorization", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
134
|
+
const data = yield (0, login_1.oidcLogin)(loginSteps);
|
|
135
|
+
return Object.assign(Object.assign({}, data), { expiresAt: Date.now() + data.expiresIn * 1e3 });
|
|
136
|
+
}), { duration: AWS_TOKEN_EXPIRY }, (data) => (data.expiresAt ? data.expiresAt < Date.now() : true));
|
|
137
|
+
const credentials = yield exchangeForAwsCredentials(oidcResponse, {
|
|
138
|
+
accountId: args.accountId,
|
|
139
|
+
permissionSet: args.permissionSet,
|
|
140
|
+
});
|
|
141
|
+
return {
|
|
142
|
+
AWS_ACCESS_KEY_ID: credentials.roleCredentials.accessKeyId,
|
|
143
|
+
AWS_SECRET_ACCESS_KEY: credentials.roleCredentials.secretAccessKey,
|
|
144
|
+
AWS_SESSION_TOKEN: credentials.roleCredentials.sessionToken,
|
|
145
|
+
AWS_SECURITY_TOKEN: credentials.roleCredentials.sessionToken,
|
|
146
|
+
expiresAt: credentials.roleCredentials.expiration,
|
|
147
|
+
};
|
|
148
|
+
}), { duration: AWS_TOKEN_EXPIRY }, (data) => (data.expiresAt ? data.expiresAt < Date.now() : true));
|
|
149
|
+
});
|
|
150
|
+
exports.assumeRoleWithIdc = assumeRoleWithIdc;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** Copyright © 2024-present P0 Security
|
|
2
|
+
|
|
3
|
+
This file is part of @p0security/cli
|
|
4
|
+
|
|
5
|
+
@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.
|
|
6
|
+
|
|
7
|
+
@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.
|
|
8
|
+
|
|
9
|
+
You should have received a copy of the GNU General Public License along with @p0security/cli. If not, see <https://www.gnu.org/licenses/>.
|
|
10
|
+
**/
|
|
11
|
+
import { SshProvider } from "../../types/ssh";
|
|
12
|
+
import { AwsSshPermissionSpec, AwsSshRequest } from "./types";
|
|
13
|
+
export declare const awsSshProvider: SshProvider<AwsSshPermissionSpec, undefined, AwsSshRequest>;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.awsSshProvider = void 0;
|
|
13
|
+
exports.awsSshProvider = {
|
|
14
|
+
requestToSsh: (request) => {
|
|
15
|
+
const { permission, generated } = request;
|
|
16
|
+
const { instanceId, accountId, region } = permission.spec;
|
|
17
|
+
const { idc, ssh, name } = generated;
|
|
18
|
+
const { linuxUserName } = ssh;
|
|
19
|
+
const common = { linuxUserName, accountId, region, id: instanceId };
|
|
20
|
+
return !idc
|
|
21
|
+
? Object.assign(Object.assign({}, common), { role: name, type: "aws", access: "role" }) : Object.assign(Object.assign({}, common), { idc, permissionSet: name, type: "aws", access: "idc" });
|
|
22
|
+
},
|
|
23
|
+
toCliRequest: (request) => __awaiter(void 0, void 0, void 0, function* () { return (Object.assign(Object.assign({}, request), { cliLocalData: undefined })); }),
|
|
24
|
+
};
|
|
@@ -8,6 +8,9 @@ This file is part of @p0security/cli
|
|
|
8
8
|
|
|
9
9
|
You should have received a copy of the GNU General Public License along with @p0security/cli. If not, see <https://www.gnu.org/licenses/>.
|
|
10
10
|
**/
|
|
11
|
+
import { PermissionSpec } from "../../types/request";
|
|
12
|
+
import { CliPermissionSpec } from "../../types/ssh";
|
|
13
|
+
import { CommonSshPermissionSpec } from "../ssh/types";
|
|
11
14
|
export declare type AwsCredentials = {
|
|
12
15
|
AWS_ACCESS_KEY_ID: string;
|
|
13
16
|
AWS_SECRET_ACCESS_KEY: string;
|
|
@@ -38,7 +41,7 @@ export declare type AwsFederatedLogin = {
|
|
|
38
41
|
};
|
|
39
42
|
};
|
|
40
43
|
};
|
|
41
|
-
declare type AwsLogin = AwsFederatedLogin | AwsIamLogin | AwsIdcLogin;
|
|
44
|
+
export declare type AwsLogin = AwsFederatedLogin | AwsIamLogin | AwsIdcLogin;
|
|
42
45
|
export declare type AwsItemConfig = {
|
|
43
46
|
label?: string;
|
|
44
47
|
state: string;
|
|
@@ -50,21 +53,44 @@ export declare type AwsItem = {
|
|
|
50
53
|
export declare type AwsConfig = {
|
|
51
54
|
"iam-write": Record<string, AwsItemConfig>;
|
|
52
55
|
};
|
|
53
|
-
export declare type
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
};
|
|
60
|
-
type: "session";
|
|
56
|
+
export declare type AwsSshPermission = {
|
|
57
|
+
spec: CommonSshPermissionSpec & {
|
|
58
|
+
instanceId: string;
|
|
59
|
+
accountId: string;
|
|
60
|
+
region: string;
|
|
61
|
+
type: "aws";
|
|
61
62
|
};
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
63
|
+
type: "session";
|
|
64
|
+
};
|
|
65
|
+
export declare type AwsSshGenerated = {
|
|
66
|
+
name: string;
|
|
67
|
+
ssh: {
|
|
68
|
+
linuxUserName: string;
|
|
69
|
+
};
|
|
70
|
+
idc?: {
|
|
71
|
+
region: string;
|
|
72
|
+
id: string;
|
|
73
|
+
};
|
|
74
|
+
};
|
|
75
|
+
export declare type AwsSshPermissionSpec = PermissionSpec<"ssh", AwsSshPermission, AwsSshGenerated>;
|
|
76
|
+
export declare type AwsSsh = CliPermissionSpec<AwsSshPermissionSpec, undefined>;
|
|
77
|
+
export declare type BaseAwsSshRequest = {
|
|
78
|
+
linuxUserName: string;
|
|
79
|
+
accountId: string;
|
|
80
|
+
region: string;
|
|
81
|
+
id: string;
|
|
82
|
+
type: "aws";
|
|
83
|
+
};
|
|
84
|
+
export declare type AwsSshRoleRequest = BaseAwsSshRequest & {
|
|
85
|
+
role: string;
|
|
86
|
+
access: "role";
|
|
87
|
+
};
|
|
88
|
+
export declare type AwsSshIdcRequest = BaseAwsSshRequest & {
|
|
89
|
+
permissionSet: string;
|
|
90
|
+
idc: {
|
|
91
|
+
id: string;
|
|
92
|
+
region: string;
|
|
68
93
|
};
|
|
94
|
+
access: "idc";
|
|
69
95
|
};
|
|
70
|
-
export
|
|
96
|
+
export declare type AwsSshRequest = AwsSshIdcRequest | AwsSshRoleRequest;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adds an ssh public key to the user object's sshPublicKeys array in Google Workspace.
|
|
3
|
+
* GCP OS Login uses these public keys to authenticate the user.
|
|
4
|
+
* Importing the same public key multiple times is idempotent.
|
|
5
|
+
*
|
|
6
|
+
* The user account and the access token is retrieved from the gcloud CLI.
|
|
7
|
+
*
|
|
8
|
+
* Returns the posix account to use for SSH access.
|
|
9
|
+
*
|
|
10
|
+
* See https://cloud.google.com/compute/docs/oslogin/rest/v1/users/importSshPublicKey
|
|
11
|
+
*/
|
|
12
|
+
export declare const importSshKey: (publicKey: string, options?: {
|
|
13
|
+
debug?: boolean;
|
|
14
|
+
}) => Promise<string>;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.importSshKey = void 0;
|
|
13
|
+
/** Copyright © 2024-present P0 Security
|
|
14
|
+
|
|
15
|
+
This file is part of @p0security/cli
|
|
16
|
+
|
|
17
|
+
@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.
|
|
18
|
+
|
|
19
|
+
@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.
|
|
20
|
+
|
|
21
|
+
You should have received a copy of the GNU General Public License along with @p0security/cli. If not, see <https://www.gnu.org/licenses/>.
|
|
22
|
+
**/
|
|
23
|
+
const subprocess_1 = require("../../common/subprocess");
|
|
24
|
+
const stdio_1 = require("../../drivers/stdio");
|
|
25
|
+
/**
|
|
26
|
+
* Adds an ssh public key to the user object's sshPublicKeys array in Google Workspace.
|
|
27
|
+
* GCP OS Login uses these public keys to authenticate the user.
|
|
28
|
+
* Importing the same public key multiple times is idempotent.
|
|
29
|
+
*
|
|
30
|
+
* The user account and the access token is retrieved from the gcloud CLI.
|
|
31
|
+
*
|
|
32
|
+
* Returns the posix account to use for SSH access.
|
|
33
|
+
*
|
|
34
|
+
* See https://cloud.google.com/compute/docs/oslogin/rest/v1/users/importSshPublicKey
|
|
35
|
+
*/
|
|
36
|
+
const importSshKey = (publicKey, options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
37
|
+
var _a;
|
|
38
|
+
const debug = (_a = options === null || options === void 0 ? void 0 : options.debug) !== null && _a !== void 0 ? _a : false;
|
|
39
|
+
// Force debug=false otherwise it prints the access token
|
|
40
|
+
const accessToken = yield (0, subprocess_1.asyncSpawn)({ debug: false }, "gcloud", [
|
|
41
|
+
"auth",
|
|
42
|
+
"print-access-token",
|
|
43
|
+
]);
|
|
44
|
+
const account = yield (0, subprocess_1.asyncSpawn)({ debug }, "gcloud", [
|
|
45
|
+
"config",
|
|
46
|
+
"get-value",
|
|
47
|
+
"account",
|
|
48
|
+
]);
|
|
49
|
+
if (debug) {
|
|
50
|
+
(0, stdio_1.print2)(`Retrieved access token ${accessToken.slice(0, 10)}... for account ${account}`);
|
|
51
|
+
}
|
|
52
|
+
const url = `https://oslogin.googleapis.com/v1/users/${account}:importSshPublicKey`;
|
|
53
|
+
const response = yield fetch(url, {
|
|
54
|
+
method: "POST",
|
|
55
|
+
body: JSON.stringify({
|
|
56
|
+
key: publicKey,
|
|
57
|
+
}),
|
|
58
|
+
headers: {
|
|
59
|
+
Authorization: `Bearer ${accessToken}`,
|
|
60
|
+
"Content-Type": "application/json",
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
const data = yield response.json();
|
|
64
|
+
if (debug) {
|
|
65
|
+
(0, stdio_1.print2)(`Login profile for user after importing public key: ${JSON.stringify(data)}`);
|
|
66
|
+
}
|
|
67
|
+
const { loginProfile } = data;
|
|
68
|
+
// Find the primary POSIX account for the user, or the first in the array
|
|
69
|
+
const linuxAccounts = loginProfile.posixAccounts.filter((account) => account.operatingSystemType === "LINUX");
|
|
70
|
+
const posixAccount = linuxAccounts.find((account) => account.primary) ||
|
|
71
|
+
loginProfile.posixAccounts[0];
|
|
72
|
+
if (debug) {
|
|
73
|
+
(0, stdio_1.print2)(`Picked linux user name: ${posixAccount === null || posixAccount === void 0 ? void 0 : posixAccount.username}`);
|
|
74
|
+
}
|
|
75
|
+
if (!posixAccount) {
|
|
76
|
+
throw "No POSIX accounts configured for the user. Ask your Google Workspace administrator to configure the user's POSIX account.";
|
|
77
|
+
}
|
|
78
|
+
return posixAccount.username;
|
|
79
|
+
});
|
|
80
|
+
exports.importSshKey = importSshKey;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** Copyright © 2024-present P0 Security
|
|
2
|
+
|
|
3
|
+
This file is part of @p0security/cli
|
|
4
|
+
|
|
5
|
+
@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.
|
|
6
|
+
|
|
7
|
+
@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.
|
|
8
|
+
|
|
9
|
+
You should have received a copy of the GNU General Public License along with @p0security/cli. If not, see <https://www.gnu.org/licenses/>.
|
|
10
|
+
**/
|
|
11
|
+
import { SshProvider } from "../../types/ssh";
|
|
12
|
+
import { GcpSshPermissionSpec, GcpSshRequest } from "./types";
|
|
13
|
+
export declare const gcpSshProvider: SshProvider<GcpSshPermissionSpec, {
|
|
14
|
+
linuxUserName: string;
|
|
15
|
+
}, GcpSshRequest>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.gcpSshProvider = void 0;
|
|
13
|
+
const ssh_key_1 = require("./ssh-key");
|
|
14
|
+
exports.gcpSshProvider = {
|
|
15
|
+
requestToSsh: (request) => {
|
|
16
|
+
return {
|
|
17
|
+
id: request.permission.spec.instanceName,
|
|
18
|
+
projectId: request.permission.spec.projectId,
|
|
19
|
+
zone: request.permission.spec.zone,
|
|
20
|
+
linuxUserName: request.cliLocalData.linuxUserName,
|
|
21
|
+
type: "gcloud",
|
|
22
|
+
};
|
|
23
|
+
},
|
|
24
|
+
toCliRequest: (request, options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
25
|
+
return (Object.assign(Object.assign({}, request), { cliLocalData: {
|
|
26
|
+
linuxUserName: yield (0, ssh_key_1.importSshKey)(request.permission.spec.publicKey, options),
|
|
27
|
+
} }));
|
|
28
|
+
}),
|
|
29
|
+
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/** Copyright © 2024-present P0 Security
|
|
2
|
+
|
|
3
|
+
This file is part of @p0security/cli
|
|
4
|
+
|
|
5
|
+
@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.
|
|
6
|
+
|
|
7
|
+
@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.
|
|
8
|
+
|
|
9
|
+
You should have received a copy of the GNU General Public License along with @p0security/cli. If not, see <https://www.gnu.org/licenses/>.
|
|
10
|
+
**/
|
|
11
|
+
import { PermissionSpec } from "../../types/request";
|
|
12
|
+
import { CliPermissionSpec } from "../../types/ssh";
|
|
13
|
+
import { CommonSshPermissionSpec } from "../ssh/types";
|
|
14
|
+
export declare type GcpSshPermission = {
|
|
15
|
+
spec: CommonSshPermissionSpec & {
|
|
16
|
+
instanceName: string;
|
|
17
|
+
projectId: string;
|
|
18
|
+
zone: string;
|
|
19
|
+
type: "gcloud";
|
|
20
|
+
};
|
|
21
|
+
type: "session";
|
|
22
|
+
};
|
|
23
|
+
export declare type GcpSshPermissionSpec = PermissionSpec<"ssh", GcpSshPermission>;
|
|
24
|
+
export declare type GcpSsh = CliPermissionSpec<GcpSshPermissionSpec, {
|
|
25
|
+
linuxUserName: string;
|
|
26
|
+
}>;
|
|
27
|
+
export declare type GcpSshRequest = {
|
|
28
|
+
linuxUserName: string;
|
|
29
|
+
projectId: string;
|
|
30
|
+
zone: string;
|
|
31
|
+
id: string;
|
|
32
|
+
type: "gcloud";
|
|
33
|
+
};
|
|
34
|
+
declare type PosixAccount = {
|
|
35
|
+
username: string;
|
|
36
|
+
uid: string;
|
|
37
|
+
gid: string;
|
|
38
|
+
operatingSystemType: "LINUX" | "OPERATING_SYSTEM_TYPE_UNSPECIFIED" | "WINDOWS";
|
|
39
|
+
homeDirectory?: string;
|
|
40
|
+
primary?: boolean;
|
|
41
|
+
};
|
|
42
|
+
declare type SshPublicKey = {
|
|
43
|
+
key: string;
|
|
44
|
+
fingerprint?: string;
|
|
45
|
+
expirationTimeUsec?: number;
|
|
46
|
+
};
|
|
47
|
+
declare type LoginProfile = {
|
|
48
|
+
name: string;
|
|
49
|
+
posixAccounts: PosixAccount[];
|
|
50
|
+
sshPublicKeys: {
|
|
51
|
+
[fingerprint: string]: SshPublicKey;
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
export declare type ImportSshPublicKeyResponse = {
|
|
55
|
+
loginProfile: LoginProfile;
|
|
56
|
+
};
|
|
57
|
+
export {};
|
package/dist/plugins/login.d.ts
CHANGED
|
@@ -10,4 +10,7 @@ You should have received a copy of the GNU General Public License along with @p0
|
|
|
10
10
|
**/
|
|
11
11
|
import { TokenResponse } from "../types/oidc";
|
|
12
12
|
import { OrgData } from "../types/org";
|
|
13
|
+
declare const loginPlugins: readonly ["google", "okta", "ping", "oidc-pkce", "microsoft", "azure-oidc", "google-oidc", "aws-oidc"];
|
|
14
|
+
export declare type LoginPluginType = (typeof loginPlugins)[number];
|
|
13
15
|
export declare const pluginLoginMap: Record<string, (org: OrgData) => Promise<TokenResponse>>;
|
|
16
|
+
export {};
|
package/dist/plugins/login.js
CHANGED
|
@@ -13,6 +13,16 @@ exports.pluginLoginMap = void 0;
|
|
|
13
13
|
const login_1 = require("./google/login");
|
|
14
14
|
const login_2 = require("./okta/login");
|
|
15
15
|
const login_3 = require("./ping/login");
|
|
16
|
+
const loginPlugins = [
|
|
17
|
+
"google",
|
|
18
|
+
"okta",
|
|
19
|
+
"ping",
|
|
20
|
+
"oidc-pkce",
|
|
21
|
+
"microsoft",
|
|
22
|
+
"azure-oidc",
|
|
23
|
+
"google-oidc",
|
|
24
|
+
"aws-oidc",
|
|
25
|
+
];
|
|
16
26
|
exports.pluginLoginMap = {
|
|
17
27
|
google: login_1.googleLogin,
|
|
18
28
|
okta: login_2.oktaLogin,
|
|
@@ -1,5 +1,36 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { AuthorizeResponse, OidcLoginSteps } from "../../types/oidc";
|
|
2
2
|
import { OrgData } from "../../types/org";
|
|
3
|
+
export declare const DEVICE_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:device_code";
|
|
3
4
|
export declare const validateProviderDomain: (org: OrgData) => void;
|
|
5
|
+
/** Executes the first step of a device-authorization grant flow */
|
|
6
|
+
export declare const authorize: <T>(request: {
|
|
7
|
+
url: string;
|
|
8
|
+
init: RequestInit;
|
|
9
|
+
}, validateResponse: (response: Response) => Promise<Response>) => Promise<T>;
|
|
10
|
+
/** Attempts to fetch this device's OIDC token
|
|
11
|
+
*
|
|
12
|
+
* The authorization may or may not be granted at this stage. If it is not, the
|
|
13
|
+
* authorization server will return "authorization_pending", in which case this
|
|
14
|
+
* function will return undefined.
|
|
15
|
+
*/
|
|
16
|
+
export declare const fetchOidcToken: <T>(request: {
|
|
17
|
+
url: string;
|
|
18
|
+
init: RequestInit;
|
|
19
|
+
}) => Promise<T | undefined>;
|
|
20
|
+
/** Waits until user device authorization is complete
|
|
21
|
+
*
|
|
22
|
+
* Returns the OIDC token after completion.
|
|
23
|
+
*/
|
|
24
|
+
export declare const waitForActivation: <A, T>(authorize: A, extractExpiryInterval: (authorize: A) => {
|
|
25
|
+
expires_in: number;
|
|
26
|
+
interval: number;
|
|
27
|
+
}, tokenRequest: {
|
|
28
|
+
url: string;
|
|
29
|
+
init: RequestInit;
|
|
30
|
+
}) => Promise<NonNullable<Awaited<T>>>;
|
|
31
|
+
export declare const oidcLoginSteps: (org: OrgData, scope: string, urls: () => {
|
|
32
|
+
deviceAuthorizationUrl: string;
|
|
33
|
+
tokenUrl: string;
|
|
34
|
+
}) => OidcLoginSteps<AuthorizeResponse>;
|
|
4
35
|
/** Logs in to an Identity Provider via OIDC */
|
|
5
|
-
export declare const oidcLogin:
|
|
36
|
+
export declare const oidcLogin: <A, T>(steps: OidcLoginSteps<A>) => Promise<NonNullable<Awaited<T>>>;
|