microsoft/TypeAgent

Public

mirrored from https://github.com/microsoft/TypeAgentAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
29a868143c97c2a7ac2ed10670b9797ca7be3785

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

ts/tools/scripts/elevate.js

231lines · modecode

1#!/usr/bin/env node
2// Copyright (c) Microsoft Corporation.
3// Licensed under the MIT License.
4
5// More info on JS Azure Auth: https://github.com/Azure/azure-sdk-for-js/blob/@azure/identity_4.4.1/sdk/identity/identity/samples/AzureIdentityExamples.md
6const { AuthorizationManagementClient } = require("@azure/arm-authorization");
7const {
8 DefaultAzureCredential,
9 InteractiveBrowserCredential,
10} = require("@azure/identity");
11
12const { executionAsyncId } = require("async_hooks");
13const child_process = require("child_process");
14const config = require("./elevate.config.json");
15const { randomUUID } = require("crypto");
16
17class AzPIMClient {
18 static async get() {
19 // We use this to validate that the user is logged in (already ran `az login`).
20 try {
21 const account = JSON.parse(await execAsync("az account show"));
22 console.log(`Logged in as ${account.user.name}`);
23 } catch (e) {
24 console.log(e);
25 console.error(
26 "ERROR: User not logged in to Azure CLI. Run 'az login'.",
27 );
28 process.exit(1);
29 }
30
31 return new AzPIMClient();
32 }
33
34 // More details on elevation here: https://learn.microsoft.com/en-us/rest/api/authorization/role-assignment-schedule-requests/create?view=rest-authorization-2020-10-01&tabs=JavaScript&tryIt=true&source=docs#code-try-0
35 // More details on role schedule requests here: https://learn.microsoft.com/en-us/javascript/api/@azure/arm-authorization/roleassignmentschedulerequests?view=azure-node-latest
36 async elevate() {
37 const credential = new DefaultAzureCredential();
38 const subscriptionId = await this.getSubscriptionId();
39 const scope = `/subscriptions/${subscriptionId}`;
40
41 // ARM client
42 const client = new AuthorizationManagementClient(
43 credential,
44 subscriptionId,
45 );
46
47 // describe elevation
48 console.log("Looking up role information...");
49 const roleAssignmentScheduleRequestName = randomUUID();
50 const parameters = {
51 principalId: await this.getPrincipalId(),
52 requestType: config.properties.RequestType,
53 roleDefinitionId: await this.getRoleDefinitionId(
54 client,
55 config.roleName,
56 scope,
57 ),
58 scheduleInfo: {
59 expiration: {
60 type: config.properties.ScheduleInfo.Expiration.Type,
61 duration:
62 config.properties.ScheduleInfo.Expiration.Duration,
63 endDateTime: null,
64 },
65 startDateTime: new Date(),
66 },
67 justification: "self elevate from typeagent script",
68 };
69
70 console.log(
71 `Elevating ${parameters.principalId} to ${config.roleName} for ${config.properties.ScheduleInfo.Expiration.Duration}`,
72 );
73
74 // elevate
75 try {
76 const result = await client.roleAssignmentScheduleRequests.create(
77 scope,
78 roleAssignmentScheduleRequestName,
79 parameters,
80 );
81
82 console.log(result);
83 console.log("ELEVATION SUCCESSFUL");
84 } catch (e) {
85 console.log(e);
86 console.log("Unable to elevate.");
87 }
88 }
89
90 async getRoleDefinitionId(client, roleName, scope) {
91 const filter = "asTarget()";
92 const options = {
93 filter,
94 };
95 var role;
96
97 for await (let item of client.roleEligibilitySchedules.listForScope(
98 scope,
99 options,
100 )) {
101 if (
102 item.expandedProperties.roleDefinition.displayName == roleName
103 ) {
104 role = item;
105 }
106 }
107
108 if (role) {
109 console.log(
110 `Found Role Definition ${roleName} with id ${role.expandedProperties.roleDefinition.id}`,
111 );
112 return role.expandedProperties.roleDefinition.id;
113 } else {
114 console.log(
115 "Unable to find the requested role. Are you certain you are logged into the correct [default] subscription?",
116 );
117 process.exit(12);
118 }
119 }
120
121 async getSubscriptionId() {
122 var subscriptionId, subscriptionName;
123
124 try {
125 const subscriptions = JSON.parse(
126 await execAsync("az account list"),
127 );
128
129 subscriptions.forEach((subscription) => {
130 if (subscription.isDefault) {
131 subscriptionId = subscription.id;
132 subscriptionName = subscription.name;
133 }
134 });
135 } catch (e) {
136 console.log(e);
137 console.error(
138 "ERROR - unable to get principal id of the current user.",
139 );
140
141 process.exit(10);
142 }
143
144 if (subscriptionId) {
145 console.log(
146 `Using subscription ${subscriptionName} [${subscriptionId}].`,
147 );
148 return subscriptionId;
149 } else {
150 console.log(
151 "Unable to find default subscription! Unable to continue.",
152 );
153 process.exit(11);
154 }
155 }
156
157 async getPrincipalId() {
158 try {
159 const accountDetails = JSON.parse(
160 await execAsync("az ad signed-in-user show"),
161 );
162
163 return accountDetails.id;
164 } catch (e) {
165 console.log(e);
166 console.error(
167 "ERROR - unable to get principal id of the current user.",
168 );
169
170 process.exit(10);
171 }
172 }
173}
174
175async function execAsync(command, options) {
176 return new Promise((res, rej) => {
177 child_process.exec(command, options, (err, stdout, stderr) => {
178 if (err) {
179 rej(err);
180 return;
181 }
182 if (stderr) {
183 console.log(stderr + stdout);
184 }
185 res(stdout);
186 });
187 });
188}
189
190async function getClient() {
191 return AzPIMClient.get();
192}
193
194async function elevate() {
195 // get PIM client
196 const client = await getClient();
197
198 // elevate
199 var v = await client.elevate();
200}
201
202(async () => {
203 const command = process.argv[2];
204 switch (command) {
205 case "help":
206 console.log("elevate");
207 console.log(
208 "Uses the logged in account to elevate. Will prompt for login if the user is not logged in.",
209 );
210 console.log("Uses configuration from elevate.config.json.");
211 return;
212 default:
213 await elevate();
214 break;
215 }
216})().catch((e) => {
217 if (
218 e.message.includes(
219 "'az' is not recognized as an internal or external command",
220 )
221 ) {
222 console.error(
223 `ERROR: Azure CLI is not installed. Install it and run 'az login' before running this tool.`,
224 );
225
226 exit(0);
227 }
228
229 console.error(`FATAL ERROR: ${e.stack}`);
230 process.exit(-1);
231});
232