opal-security 2.0.19 → 2.1.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/README.md +24 -26
- package/lib/commands/iam-roles/start.js +30 -125
- package/lib/commands/kube-roles/start.js +23 -122
- package/lib/commands/login.d.ts +3 -1
- package/lib/commands/login.js +35 -24
- package/lib/commands/postgres-instances/start.js +59 -134
- package/lib/commands/resources/get.d.ts +1 -1
- package/lib/commands/resources/get.js +19 -1
- package/lib/commands/set-url.d.ts +6 -3
- package/lib/commands/set-url.js +36 -12
- package/lib/commands/ssh/copyFrom.js +18 -67
- package/lib/commands/ssh/copyTo.js +18 -67
- package/lib/commands/ssh/start.d.ts +1 -0
- package/lib/commands/ssh/start.js +33 -80
- package/lib/handler.d.ts +1 -2
- package/lib/handler.js +0 -27
- package/lib/lib/apollo.d.ts +2 -1
- package/lib/lib/apollo.js +64 -22
- package/lib/lib/aws.js +3 -2
- package/lib/lib/cmd.d.ts +0 -11
- package/lib/lib/cmd.js +3 -15
- package/lib/lib/common.d.ts +4 -3
- package/lib/lib/common.js +33 -15
- package/lib/lib/resources.d.ts +13 -5
- package/lib/lib/resources.js +83 -23
- package/lib/lib/sessions.d.ts +4 -0
- package/lib/lib/sessions.js +154 -0
- package/lib/lib/ssh.d.ts +1 -3
- package/lib/lib/ssh.js +3 -49
- package/lib/types.d.ts +1 -0
- package/oclif.manifest.json +1 -1
- package/package.json +3 -2
package/lib/lib/resources.js
CHANGED
|
@@ -1,22 +1,81 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.promptUserForAccessLevels = exports.
|
|
4
|
-
const cmd_1 = require("./cmd");
|
|
3
|
+
exports.promptUserForAccessLevels = exports.promptUserForResource = exports.filterChoices = exports.DEFAULT_ACCESS_LEVEL = void 0;
|
|
5
4
|
const handler_1 = require("../handler");
|
|
6
5
|
const apollo_1 = require("./apollo");
|
|
7
6
|
const inquirer = require("inquirer");
|
|
8
|
-
exports.
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
exports.DEFAULT_ACCESS_LEVEL = {
|
|
8
|
+
accessLevelName: '',
|
|
9
|
+
accessLevelRemoteId: '',
|
|
10
|
+
};
|
|
11
|
+
// Returns a filtered array of items that match the input
|
|
12
|
+
exports.filterChoices = (input, choices) => {
|
|
13
|
+
input = input || '';
|
|
14
|
+
if (input === '') {
|
|
15
|
+
return choices;
|
|
12
16
|
}
|
|
13
|
-
return
|
|
17
|
+
return choices.filter(choice => choice.name.toLowerCase().includes(input.toLowerCase()));
|
|
14
18
|
};
|
|
15
|
-
|
|
16
|
-
|
|
19
|
+
const ListResourcesDocumentTemplate = `
|
|
20
|
+
query ListResources {
|
|
21
|
+
resources(input: {resourceTypes: [RESOURCE_TYPE], onlyMine: true, maxNumEntries: 1000}) {
|
|
22
|
+
__typename
|
|
23
|
+
... on ResourcesResult {
|
|
24
|
+
resources {
|
|
25
|
+
name
|
|
26
|
+
id
|
|
27
|
+
parentResource {
|
|
28
|
+
name
|
|
29
|
+
}
|
|
30
|
+
connection {
|
|
31
|
+
name
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
cursor
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}`;
|
|
38
|
+
exports.promptUserForResource = async (command, resourceType, message) => {
|
|
39
|
+
const listResourcesDocument = ListResourcesDocumentTemplate.replace('RESOURCE_TYPE', resourceType);
|
|
40
|
+
const { resp, error } = await handler_1.runQuery({
|
|
41
|
+
command: command,
|
|
42
|
+
query: listResourcesDocument,
|
|
43
|
+
variables: {},
|
|
44
|
+
});
|
|
45
|
+
if (error) {
|
|
46
|
+
return apollo_1.handleError(command, error, resp);
|
|
47
|
+
}
|
|
48
|
+
const resourceInfos = resp === null || resp === void 0 ? void 0 : resp.data.resources.resources.map((resource) => {
|
|
49
|
+
let name = resource.name;
|
|
50
|
+
if (resource.parentResource) {
|
|
51
|
+
name = `[${resource.parentResource.name}] ${name}`;
|
|
52
|
+
}
|
|
53
|
+
else if (resource.connection) {
|
|
54
|
+
name = `[${resource.connection.name}] ${name}`;
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
id: resource.id,
|
|
58
|
+
name: name,
|
|
59
|
+
};
|
|
60
|
+
});
|
|
61
|
+
if (resourceInfos.length === 0) {
|
|
62
|
+
return apollo_1.handleError(command, 'Oh no! You don\'t have access to any resources. Please go to Opal to request access.');
|
|
63
|
+
}
|
|
64
|
+
const resourceInfoByName = {};
|
|
65
|
+
resourceInfos.forEach(resourceInfo => {
|
|
66
|
+
resourceInfoByName[resourceInfo.name] = resourceInfo;
|
|
67
|
+
});
|
|
68
|
+
inquirer.registerPrompt('autocomplete', require('inquirer-autocomplete-prompt'));
|
|
69
|
+
const selectedResourceInfo = await inquirer.prompt([{
|
|
70
|
+
name: 'resource',
|
|
71
|
+
message: message,
|
|
72
|
+
type: 'autocomplete',
|
|
73
|
+
source: (answers, input) => exports.filterChoices(input, resourceInfos),
|
|
74
|
+
}]);
|
|
75
|
+
return resourceInfoByName[selectedResourceInfo.resource];
|
|
17
76
|
};
|
|
18
|
-
const
|
|
19
|
-
query
|
|
77
|
+
const ListAccessLevelsForResource = `
|
|
78
|
+
query ListAccessLevelsForResource($resourceId: ResourceId!) {
|
|
20
79
|
accessLevels(input: {resourceId: $resourceId, onlyMine: true}) {
|
|
21
80
|
__typename
|
|
22
81
|
... on ResourceAccessLevelsResult {
|
|
@@ -27,23 +86,23 @@ query ListAccessRolesForResource($resourceId: ResourceId!) {
|
|
|
27
86
|
}
|
|
28
87
|
}
|
|
29
88
|
}`;
|
|
30
|
-
exports.promptUserForAccessLevels = async (
|
|
89
|
+
exports.promptUserForAccessLevels = async (command, resourceId, instanceType, accessLevelRemoteId) => {
|
|
31
90
|
var _a, _b, _c;
|
|
32
|
-
const { resp
|
|
33
|
-
command:
|
|
34
|
-
query:
|
|
91
|
+
const { resp, error } = await handler_1.runQuery({
|
|
92
|
+
command: command,
|
|
93
|
+
query: ListAccessLevelsForResource,
|
|
35
94
|
variables: { resourceId },
|
|
36
95
|
});
|
|
37
|
-
if (
|
|
38
|
-
apollo_1.
|
|
39
|
-
return null;
|
|
96
|
+
if (error) {
|
|
97
|
+
return apollo_1.handleError(command, error, resp);
|
|
40
98
|
}
|
|
41
|
-
const accessLevelInfos = (_c = (_b = (_a =
|
|
99
|
+
const accessLevelInfos = (_c = (_b = (_a = resp === null || resp === void 0 ? void 0 : resp.data) === null || _a === void 0 ? void 0 : _a.accessLevels) === null || _b === void 0 ? void 0 : _b.accessLevels) === null || _c === void 0 ? void 0 : _c.map((resp) => ({
|
|
100
|
+
id: resp.accessLevelRemoteId,
|
|
101
|
+
name: resp.accessLevelName,
|
|
102
|
+
}));
|
|
42
103
|
if (!accessLevelInfos) {
|
|
43
|
-
|
|
44
|
-
return null;
|
|
104
|
+
return apollo_1.handleError(command, 'Oh no! We weren\'t expecting the amount of access levels returned from Opal. Please contact your support engineer.');
|
|
45
105
|
}
|
|
46
|
-
// Prompt user to pick access levels available to them
|
|
47
106
|
const accessLevelInfoByName = {};
|
|
48
107
|
const accessLevelInfoByRemoteId = {};
|
|
49
108
|
accessLevelInfos.forEach(accessLevelInfo => {
|
|
@@ -54,13 +113,14 @@ exports.promptUserForAccessLevels = async (context, resourceId, instanceType, ac
|
|
|
54
113
|
if (accessLevelRemoteId) {
|
|
55
114
|
selectedAccessLevel = accessLevelInfoByRemoteId[accessLevelRemoteId];
|
|
56
115
|
}
|
|
116
|
+
// Prompt user to pick access levels available to them
|
|
57
117
|
if (!selectedAccessLevel) {
|
|
58
118
|
inquirer.registerPrompt('autocomplete', require('inquirer-autocomplete-prompt'));
|
|
59
119
|
const selectedAccessLevelInfo = await inquirer.prompt([{
|
|
60
120
|
name: 'accessLevel',
|
|
61
121
|
message: `Select an access level to the ${instanceType}`,
|
|
62
122
|
type: 'autocomplete',
|
|
63
|
-
source: (answers, input) =>
|
|
123
|
+
source: (answers, input) => exports.filterChoices(input, accessLevelInfos),
|
|
64
124
|
}]);
|
|
65
125
|
selectedAccessLevel = accessLevelInfoByName[selectedAccessLevelInfo.accessLevel];
|
|
66
126
|
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import Command from '@oclif/command';
|
|
2
|
+
import { ResourceAccessLevelInput } from '../types';
|
|
3
|
+
export declare const getOrCreateSession: (command: Command, resourceId: string, accessLevel: ResourceAccessLevelInput, sessionId: string | undefined, metadataFragment: string) => Promise<any>;
|
|
4
|
+
export declare const getSessionExpirationMessage: (session: any) => string;
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getSessionExpirationMessage = exports.getOrCreateSession = void 0;
|
|
4
|
+
const open = require("open");
|
|
5
|
+
const config_1 = require("../lib/config");
|
|
6
|
+
const handler_1 = require("../handler");
|
|
7
|
+
const moment = require("moment");
|
|
8
|
+
const apollo_1 = require("../lib/apollo");
|
|
9
|
+
const common_1 = require("../lib/common");
|
|
10
|
+
const CreateSessionDocument = `
|
|
11
|
+
mutation CreateSession($id: ResourceId!, $accessLevel: ResourceAccessLevelInput!, $sessionId: SessionId) {
|
|
12
|
+
createSession(input: {resourceId: $id, accessLevel: $accessLevel, sessionId: $sessionId}) {
|
|
13
|
+
__typename
|
|
14
|
+
... on CreateSessionResult {
|
|
15
|
+
session {
|
|
16
|
+
id
|
|
17
|
+
accessLevelRemoteId
|
|
18
|
+
endTime
|
|
19
|
+
metadata {
|
|
20
|
+
METADATA_FRAGMENT
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
... on SessionNotFoundError {
|
|
25
|
+
message
|
|
26
|
+
}
|
|
27
|
+
... on MfaInvalidError {
|
|
28
|
+
message
|
|
29
|
+
}
|
|
30
|
+
... on OidcIDTokenNotFoundError {
|
|
31
|
+
message
|
|
32
|
+
}
|
|
33
|
+
... on ResourceNotFoundError {
|
|
34
|
+
message
|
|
35
|
+
}
|
|
36
|
+
... on EndSystemAuthorizationError {
|
|
37
|
+
message
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
`;
|
|
42
|
+
const ListSessionsDocument = `
|
|
43
|
+
query ListSessions($id: ResourceId!) {
|
|
44
|
+
sessions(input: {resourceId: $id}) {
|
|
45
|
+
__typename
|
|
46
|
+
... on SessionsResult {
|
|
47
|
+
sessions {
|
|
48
|
+
id
|
|
49
|
+
accessLevelRemoteId
|
|
50
|
+
endTime
|
|
51
|
+
metadata {
|
|
52
|
+
METADATA_FRAGMENT
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
`;
|
|
59
|
+
const getSession = async (command, resourceId, accessLevelRemoteId, sessionId, metadataFragment) => {
|
|
60
|
+
const { resp, error } = await handler_1.runQuery({
|
|
61
|
+
command: command,
|
|
62
|
+
query: ListSessionsDocument.replace('METADATA_FRAGMENT', metadataFragment),
|
|
63
|
+
variables: {
|
|
64
|
+
id: resourceId,
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
if (error) {
|
|
68
|
+
return apollo_1.handleError(command, error);
|
|
69
|
+
}
|
|
70
|
+
switch (resp === null || resp === void 0 ? void 0 : resp.data.sessions.__typename) {
|
|
71
|
+
case 'SessionsResult': {
|
|
72
|
+
const sessions = resp.data.sessions.sessions;
|
|
73
|
+
let selectedSession;
|
|
74
|
+
for (const session of sessions) {
|
|
75
|
+
if (sessionId && session.id !== sessionId) {
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if (session.accessLevelRemoteId !== accessLevelRemoteId) {
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
if (!selectedSession || moment(session.endTime).diff(selectedSession.endTime) > 0) {
|
|
82
|
+
// Select the session with the latest end time
|
|
83
|
+
selectedSession = session;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return selectedSession;
|
|
87
|
+
}
|
|
88
|
+
default:
|
|
89
|
+
return apollo_1.handleError(command, error, resp);
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
const openBrowserAndPollForSession = async (command, message, resourceId, accessLevelRemoteId, sessionId, metadataFragment) => {
|
|
93
|
+
command.log(message);
|
|
94
|
+
const configData = config_1.getOrCreateConfigData(command.config.configDir);
|
|
95
|
+
const url = configData[config_1.urlKey];
|
|
96
|
+
setTimeout(() => {
|
|
97
|
+
open(url + `/resources/${resourceId}?showModal=true`);
|
|
98
|
+
}, 2000); // Wait before opening the browser to give the user time to read the message
|
|
99
|
+
let session;
|
|
100
|
+
while (!session) {
|
|
101
|
+
// eslint-disable-next-line no-await-in-loop
|
|
102
|
+
await common_1.sleep(2000);
|
|
103
|
+
// eslint-disable-next-line no-await-in-loop
|
|
104
|
+
session = await getSession(command, resourceId, accessLevelRemoteId, sessionId, metadataFragment);
|
|
105
|
+
}
|
|
106
|
+
return session;
|
|
107
|
+
};
|
|
108
|
+
const createSession = async (command, resourceId, accessLevel, sessionId, metadataFragment) => {
|
|
109
|
+
const { resp, error } = await handler_1.runMutation({
|
|
110
|
+
command: command,
|
|
111
|
+
query: CreateSessionDocument.replace('METADATA_FRAGMENT', metadataFragment),
|
|
112
|
+
variables: {
|
|
113
|
+
id: resourceId,
|
|
114
|
+
accessLevel: accessLevel,
|
|
115
|
+
sessionId,
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
if (error) {
|
|
119
|
+
return apollo_1.handleError(command, error);
|
|
120
|
+
}
|
|
121
|
+
switch (resp === null || resp === void 0 ? void 0 : resp.data.createSession.__typename) {
|
|
122
|
+
case 'CreateSessionResult': {
|
|
123
|
+
return resp.data.createSession.session;
|
|
124
|
+
}
|
|
125
|
+
case 'MfaInvalidError': {
|
|
126
|
+
command.log();
|
|
127
|
+
return openBrowserAndPollForSession(command, '❗ MFA validation needed. Please connect via browser. Opening browser and awaiting validation...', resourceId, accessLevel.accessLevelRemoteId, sessionId, metadataFragment);
|
|
128
|
+
}
|
|
129
|
+
case 'OidcIDTokenNotFoundError': {
|
|
130
|
+
command.log();
|
|
131
|
+
return openBrowserAndPollForSession(command, '❗ OIDC authentication needed. Please connect via browser. Opening browser and awaiting authentication...', resourceId, accessLevel.accessLevelRemoteId, sessionId, metadataFragment);
|
|
132
|
+
}
|
|
133
|
+
default:
|
|
134
|
+
return apollo_1.handleError(command, error, resp);
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
exports.getOrCreateSession = async (command, resourceId, accessLevel, sessionId, metadataFragment) => {
|
|
138
|
+
// Use existing session if it exists
|
|
139
|
+
const existingSession = await getSession(command, resourceId, accessLevel.accessLevelRemoteId, sessionId, metadataFragment);
|
|
140
|
+
if (existingSession) {
|
|
141
|
+
return existingSession;
|
|
142
|
+
}
|
|
143
|
+
if (sessionId) {
|
|
144
|
+
return apollo_1.handleError(command, 'Session not found for given id: ' + sessionId);
|
|
145
|
+
}
|
|
146
|
+
// Create new session
|
|
147
|
+
return createSession(command, resourceId, accessLevel, sessionId, metadataFragment);
|
|
148
|
+
};
|
|
149
|
+
exports.getSessionExpirationMessage = (session) => {
|
|
150
|
+
const diff = moment(session.endTime).diff(moment(), 'minutes');
|
|
151
|
+
const hours = Math.floor(diff / 60);
|
|
152
|
+
const minutes = diff % 60;
|
|
153
|
+
return `${hours}h ${minutes}m`;
|
|
154
|
+
};
|
package/lib/lib/ssh.d.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
1
|
import { Command } from '@oclif/command';
|
|
2
|
-
|
|
3
|
-
export declare const ListSshInstancesDocument = "\nquery ListSSHInstances {\n resources(input: {serviceType: SSH, onlyMine: true, maxNumEntries: 1000}) {\n __typename\n ... on ResourcesResult {\n resources {\n name\n id\n }\n cursor\n }\n }\n}";
|
|
4
|
-
export declare const selectComputeInstance: (command: Command, description: string) => Promise<ResourceInfo | undefined>;
|
|
2
|
+
export declare const selectComputeInstance: (command: Command, action: string) => Promise<void | import("./resources").ResourceInfo>;
|
|
5
3
|
export declare const assertSessionManagerPluginExists: () => Promise<boolean>;
|
package/lib/lib/ssh.js
CHANGED
|
@@ -1,56 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.assertSessionManagerPluginExists = exports.selectComputeInstance =
|
|
4
|
-
const handler_1 = require("../handler");
|
|
5
|
-
const apollo_1 = require("../lib/apollo");
|
|
3
|
+
exports.assertSessionManagerPluginExists = exports.selectComputeInstance = void 0;
|
|
6
4
|
const cmd_1 = require("../lib/cmd");
|
|
7
|
-
const inquirer = require("inquirer");
|
|
8
5
|
const resources_1 = require("./resources");
|
|
9
|
-
exports.
|
|
10
|
-
|
|
11
|
-
resources(input: {serviceType: SSH, onlyMine: true, maxNumEntries: 1000}) {
|
|
12
|
-
__typename
|
|
13
|
-
... on ResourcesResult {
|
|
14
|
-
resources {
|
|
15
|
-
name
|
|
16
|
-
id
|
|
17
|
-
}
|
|
18
|
-
cursor
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
}`;
|
|
22
|
-
exports.selectComputeInstance = async (command, description) => {
|
|
23
|
-
const { resp: sshInstancesResp, error } = await handler_1.runQuery({
|
|
24
|
-
command: command,
|
|
25
|
-
query: exports.ListSshInstancesDocument,
|
|
26
|
-
variables: {},
|
|
27
|
-
});
|
|
28
|
-
if (error) {
|
|
29
|
-
apollo_1.printRequestOutput(command, sshInstancesResp, error);
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
const resourceInfos = sshInstancesResp === null || sshInstancesResp === void 0 ? void 0 : sshInstancesResp.data.resources.resources.map((resource) => {
|
|
33
|
-
return {
|
|
34
|
-
id: resource.id,
|
|
35
|
-
name: resource.name,
|
|
36
|
-
};
|
|
37
|
-
});
|
|
38
|
-
const noResourcesFound = resources_1.resourcesAreEmpty(command, resourceInfos);
|
|
39
|
-
if (noResourcesFound) {
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
const resourceInfoByName = {};
|
|
43
|
-
resourceInfos.forEach(resourceInfo => {
|
|
44
|
-
resourceInfoByName[resourceInfo.name] = resourceInfo;
|
|
45
|
-
});
|
|
46
|
-
inquirer.registerPrompt('autocomplete', require('inquirer-autocomplete-prompt'));
|
|
47
|
-
const selectedInstanceInfo = await inquirer.prompt([{
|
|
48
|
-
name: 'instance',
|
|
49
|
-
message: `Select a compute instance to ${description}`,
|
|
50
|
-
type: 'autocomplete',
|
|
51
|
-
source: (answers, input) => cmd_1.filterChoices(input, resourceInfos),
|
|
52
|
-
}]);
|
|
53
|
-
return resourceInfoByName[selectedInstanceInfo.instance];
|
|
6
|
+
exports.selectComputeInstance = async (command, action) => {
|
|
7
|
+
return resources_1.promptUserForResource(command, 'AWS_EC2_INSTANCE', `Select an EC2 instance to ${action}`);
|
|
54
8
|
};
|
|
55
9
|
exports.assertSessionManagerPluginExists = async () => {
|
|
56
10
|
const errorMessage = '❗ AWS session manager plugin is required to use SSH functionality. ' +
|
package/lib/types.d.ts
CHANGED
|
@@ -4373,6 +4373,7 @@ export declare type Resource = {
|
|
|
4373
4373
|
ownerTeam?: Maybe<Group>;
|
|
4374
4374
|
connectionId: Scalars['ConnectionId'];
|
|
4375
4375
|
connection?: Maybe<Connection>;
|
|
4376
|
+
parentResource?: Maybe<Resource>;
|
|
4376
4377
|
folderId?: Maybe<Scalars['ResourceFolderId']>;
|
|
4377
4378
|
folder?: Maybe<ResourceFolder>;
|
|
4378
4379
|
resourceUsers: Array<ResourceUser>;
|
package/oclif.manifest.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"2.0
|
|
1
|
+
{"version":"2.1.0","commands":{"curl-example":{"id":"curl-example","description":"Prints out an example cURL command containing the parameters the CLI uses to query the Opal server.","pluginName":"opal-security","pluginType":"core","aliases":[],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"login":{"id":"login","description":"Authenticates you with the Opal server.","pluginName":"opal-security","pluginType":"core","aliases":[],"examples":["$ opal login"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"email":{"name":"email","type":"option","description":"Email address to login with."}},"args":[]},"logout":{"id":"logout","description":"Clears locally stored Opal server authentication credentials.","pluginName":"opal-security","pluginType":"core","aliases":[],"examples":["$ opal logout"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"set-custom-header":{"id":"set-custom-header","description":"Sets a custom HTTP header to connect to the Opal server.","pluginName":"opal-security","pluginType":"core","aliases":[],"examples":["$ opal set-custom-header --header 'cf-access-token: $TOKEN'"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"header":{"name":"header","type":"option"}},"args":[]},"set-token":{"id":"set-token","description":"Sets an API token to authenticate with the Opal server - alternative auth flow for headless environments.","pluginName":"opal-security","pluginType":"core","aliases":[],"examples":["$ opal set-token"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"set-url":{"id":"set-url","description":"Sets the url of the Opal server. Defaults to https://app.opal.dev.","pluginName":"opal-security","pluginType":"core","aliases":[],"examples":["$ opal set-url"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"allowSelfSignedCerts":{"name":"allowSelfSignedCerts","type":"boolean","allowNo":false},"custom":{"name":"custom","type":"option","hidden":true},"prod":{"name":"prod","type":"boolean","hidden":true,"allowNo":false},"demo":{"name":"demo","type":"boolean","hidden":true,"allowNo":false},"dev":{"name":"dev","type":"boolean","hidden":true,"allowNo":false},"devLocal":{"name":"devLocal","type":"boolean","hidden":true,"allowNo":false}},"args":[{"name":"url","description":"URL of the Opal server to use. If unspecified, defaults to https://app.opal.dev","required":false}]},"aws:identity":{"id":"aws:identity","description":"Gets the current caller identity for the \"opal\" AWS profile.","pluginName":"opal-security","pluginType":"core","aliases":[],"examples":["opal aws:identity"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"iam-roles:start":{"id":"iam-roles:start","description":"Starts a session to assume an IAM role.","pluginName":"opal-security","pluginType":"core","aliases":[],"examples":["opal iam-roles:start","opal iam-roles:start --id 51f7176b-0464-4a6f-8369-e951e187b398","opal iam-roles:start --id 51f7176b-0464-4a6f-8369-e951e187b398 --profileName \"custom-profile\""],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"id":{"name":"id","type":"option","description":"The ID of the Opal role resource."},"sessionId":{"name":"sessionId","type":"option","description":"SessionId of a session that has already been created via the web flow."},"profileName":{"name":"profileName","type":"option","description":"Uses a custom AWS profile name for the IAM role. Default value is the role's name."}},"args":[]},"kube-roles:start":{"id":"kube-roles:start","description":"Starts a session to assume a Kubernetes cluster IAM role.","pluginName":"opal-security","pluginType":"core","aliases":[],"examples":["opal kube-roles:start","opal kube-roles:start --id 51f7176b-0464-4a6f-8369-e951e187b398","opal kube-roles:start --id 51f7176b-0464-4a6f-8369-e951e187b398 --accessLevelRemoteId \"arn:aws:iam::712234975475:role/acme-eks-cluster-admin-role\""],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"id":{"name":"id","type":"option","description":"The ID of the Opal role resource."},"accessLevelRemoteId":{"name":"accessLevelRemoteId","type":"option","description":"The remote ID of the access level with which to access the cluster."},"sessionId":{"name":"sessionId","type":"option","description":"SessionId of a session that has already been created via the web flow."}},"args":[]},"postgres-instances:start":{"id":"postgres-instances:start","description":"Starts a session to query a Postgres database.","pluginName":"opal-security","pluginType":"core","aliases":[],"examples":["opal postgres-instances:start","opal postgres-instances:start --id 51f7176b-0464-4a6f-8369-e951e187b398","opal postgres-instances:start --id 51f7176b-0464-4a6f-8369-e951e187b398 --accessLevelRemoteId \"fullaccess\""],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"id":{"name":"id","type":"option","description":"The ID of the Opal instance resource."},"accessLevelRemoteId":{"name":"accessLevelRemoteId","type":"option","description":"The remote ID of the access level with which to access the database."},"sessionId":{"name":"sessionId","type":"option","description":"SessionId of a session that has already been created via the web flow."}},"args":[]},"resources:get":{"id":"resources:get","description":"Get resource info for a particular resource.","pluginName":"opal-security","pluginType":"core","aliases":[],"examples":["opal resources:get --id 54052a3e-5375-4392-aeaf-0c6c44c131d4"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"id":{"name":"id","type":"option","required":true}},"args":[]},"ssh:copyFrom":{"id":"ssh:copyFrom","description":"Use SCP to copy files from a compute instance.","pluginName":"opal-security","pluginType":"core","aliases":[],"examples":["opal ssh:copyFrom --src instance/dir --dest my/dir","opal ssh:copyFrom --src instance/dir --dest my/dir --id 51f7176b-0464-4a6f-8369-e951e187b398"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"src":{"name":"src","type":"option","description":"The path of the directory or file you would like to copy over SCP. Note we only support one file or directory at a time.","required":true},"dest":{"name":"dest","type":"option","description":"Pick which directory you want your files to be copied to.","required":false,"default":"."},"user":{"name":"user","type":"option","description":"Pick which user you want to run SCP over. Keep in mind not all users will have access to each other's home directory.","required":false,"default":"ssm-user"},"id":{"name":"id","type":"option","description":"The ID of the Opal instance resource."},"sessionId":{"name":"sessionId","type":"option","description":"SessionId of a session that has already been created via the web flow."}},"args":[]},"ssh:copyTo":{"id":"ssh:copyTo","description":"Use SCP to copy files to a compute instance.","pluginName":"opal-security","pluginType":"core","aliases":[],"examples":["opal ssh:copyTo --src my/dir --dest instance/dir","opal ssh:copyTo --src my/dir --dest instance/dir --id 51f7176b-0464-4a6f-8369-e951e187b398"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"src":{"name":"src","type":"option","description":"The path of the directory or file you would like to copy over SCP. Note we only support one file or directory at a time.","required":true},"dest":{"name":"dest","type":"option","description":"Pick which directory you want your files to be copied to.","required":false,"default":"."},"user":{"name":"user","type":"option","description":"Pick which user you want to run SCP over. Keep in mind not all users will have access to each other's home directory.","required":false,"default":"ssm-user"},"id":{"name":"id","type":"option","description":"The ID of the Opal instance resource."},"sessionId":{"name":"sessionId","type":"option","description":"SessionId of a session that has already been created via the web flow."}},"args":[]},"ssh:start":{"id":"ssh:start","description":"Starts an SSH session to access a compute instance.","pluginName":"opal-security","pluginType":"core","aliases":[],"examples":["opal ssh:start","opal ssh:start --id 51f7176b-0464-4a6f-8369-e951e187b398"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"id":{"name":"id","type":"option","description":"The ID of the Opal instance resource."},"sessionId":{"name":"sessionId","type":"option","description":"SessionId of a session that has already been created via the web flow."}},"args":[]}}}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opal-security",
|
|
3
3
|
"description": "Opal allows you to centrally manage access to all of your sensitive systems.",
|
|
4
|
-
"version": "2.0
|
|
4
|
+
"version": "2.1.0",
|
|
5
5
|
"author": "Stephen Cobbe",
|
|
6
6
|
"bin": {
|
|
7
7
|
"opal": "./bin/run"
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"@types/mocha": "^5.2.7",
|
|
42
42
|
"@types/node": "^14.14.37",
|
|
43
43
|
"@types/semver": "^7.3.8",
|
|
44
|
-
"@typescript-eslint/eslint-plugin": "^5.
|
|
44
|
+
"@typescript-eslint/eslint-plugin": "^5.31.0",
|
|
45
45
|
"chai": "^4.3.4",
|
|
46
46
|
"eslint": "^8.17.0",
|
|
47
47
|
"eslint-config-oclif": "^3.1.0",
|
|
@@ -81,6 +81,7 @@
|
|
|
81
81
|
"url": "https://github.com/opalsecurity/opal-cli.git"
|
|
82
82
|
},
|
|
83
83
|
"resolutions": {
|
|
84
|
+
"agent-base": "^6.0.1",
|
|
84
85
|
"ansi-regex": "5.0.1"
|
|
85
86
|
},
|
|
86
87
|
"scripts": {
|