Skip to content

Commit 05b4a65

Browse files
authored
Merge pull request #23 from cloudgraphdev/feature/CG-1320-support-access-approval
feat(CG-1320): add gcp access approval service support
2 parents 8325f18 + 65b8852 commit 05b4a65

13 files changed

Lines changed: 278 additions & 1 deletion

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ CloudGraph GCP Provider will ask you what regions you would like to crawl and wi
6464

6565
| Service | Relations |
6666
| ------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
67+
| accessApproval | project |
6768
| aiPlatformNotebooks | project, kmsCryptoKeys, network, subnet |
6869
| alertPolicy | project |
6970
| apiGatewayGateways | project, apiGatewayApis, apiGatewayApiConfigs |

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
},
3333
"dependencies": {
3434
"@cloudgraph/sdk": "0.22.1",
35+
"@google-cloud/access-approval": "^2.1.2",
3536
"@google-cloud/api-gateway": "^1.2.1",
3637
"@google-cloud/asset": "^3.22.0",
3738
"@google-cloud/bigquery": "^5.10.0",

src/enums/schemasMap.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,5 +54,6 @@ export default {
5454
[services.apiGatewayApiConfig]: 'gcpApiGatewayApiConfig',
5555
[services.firestoreDatabase]: 'gcpFirestoreDatabase',
5656
[services.essentialContacts]: 'gcpEssentialContact',
57+
[services.accessApproval]: 'gcpAccessApproval',
5758
tag: 'gcpTag',
5859
}

src/enums/serviceMap.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ import GcpLabel from '../services/label'
5151
import GcpTag from '../services/tag'
5252
import GcpBilling from '../services/billing'
5353
import GcpEssentialContacts from '../services/essentialContacts'
54+
import GcpAccessApproval from '../services/accessApproval'
5455

5556
/**
5657
* serviceMap is an object that contains all currently supported services
@@ -107,6 +108,7 @@ export default {
107108
[services.apiGatewayApiConfig]: GcpApiGatewayApiConfig,
108109
[services.firestoreDatabase]: GcpFirestoreDatabase,
109110
[services.essentialContacts]: GcpEssentialContacts,
111+
[services.accessApproval]: GcpAccessApproval,
110112
label: GcpLabel,
111113
tag: GcpTag,
112114
}

src/enums/services.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ export default {
5555
// spanner: 'spanner',
5656
// activeDirectory: 'active-directory',
5757
// identity: 'identity',
58-
// accessApproval: 'access-approval',
58+
accessApproval: 'accessApproval',
5959
// accessContextManager: 'access-context-manager',
6060
// auth: 'auth',
6161
folder: 'folder',
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { AccessApprovalClient } from '@google-cloud/access-approval'
2+
import { google } from '@google-cloud/access-approval/build/protos/protos'
3+
import CloudGraph from '@cloudgraph/sdk'
4+
import groupBy from 'lodash/groupBy'
5+
import gcpLoggerText from '../../properties/logger'
6+
import { GcpServiceInput } from '../../types'
7+
import { initTestEndpoint, generateGcpErrorLog } from '../../utils'
8+
import { GLOBAL_REGION } from '../../config/constants'
9+
10+
const lt = { ...gcpLoggerText }
11+
const { logger } = CloudGraph
12+
const serviceName = 'AccessApproval'
13+
const apiEndpoint = initTestEndpoint(serviceName)
14+
15+
export interface RawGcpAccessApproval extends google.cloud.accessapproval.v1.IApprovalRequest {
16+
id: string
17+
projectId: string
18+
region: string
19+
}
20+
21+
export default async ({
22+
config,
23+
}: GcpServiceInput): Promise<{
24+
[region: string]: RawGcpAccessApproval[]
25+
}> =>
26+
new Promise(async resolve => {
27+
const accessApprovalList: RawGcpAccessApproval[] = []
28+
const { projectId } = config
29+
30+
/**
31+
* Get all EssentialContacts
32+
*/
33+
try {
34+
const accessApprovalClient = new AccessApprovalClient({ ...config, apiEndpoint });
35+
const iterable = accessApprovalClient.listApprovalRequestsAsync({
36+
parent: `projects/${projectId}`,
37+
})
38+
39+
for await (const response of iterable) {
40+
if (response) {
41+
accessApprovalList.push({
42+
id: response.name,
43+
projectId,
44+
region: GLOBAL_REGION,
45+
...response,
46+
})
47+
}
48+
}
49+
} catch (error) {
50+
generateGcpErrorLog(serviceName, 'accessApproval:listApprovalRequestsAsync', error)
51+
}
52+
53+
logger.debug(lt.foundResources(serviceName, accessApprovalList.length))
54+
resolve(groupBy(accessApprovalList, 'region'))
55+
})
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import { google } from '@google-cloud/access-approval/build/protos/protos'
2+
import { GcpAccessApproval } from '../../types/generated'
3+
import { RawGcpAccessApproval } from './data'
4+
import { toISOString } from '../../utils/dateutils'
5+
import { enumKeyToString } from '../../utils/format'
6+
7+
export default ({
8+
service,
9+
}: {
10+
service: RawGcpAccessApproval
11+
region: string
12+
}): GcpAccessApproval => {
13+
const {
14+
id,
15+
projectId,
16+
region,
17+
name,
18+
requestedResourceName,
19+
requestedResourceProperties,
20+
requestedReason,
21+
requestedLocations,
22+
requestTime,
23+
requestedExpiration,
24+
approve,
25+
dismiss,
26+
} = service
27+
28+
return {
29+
id,
30+
projectId,
31+
region,
32+
name,
33+
requestedResourceName,
34+
requestedResourceProperties: {
35+
excludesDescendants: requestedResourceProperties?.excludesDescendants,
36+
},
37+
requestedReason: {
38+
type: enumKeyToString(google.cloud.accessapproval.v1.AccessReason.Type, requestedReason?.type),
39+
detail: requestedReason?.detail,
40+
},
41+
requestedLocations: {
42+
principalOfficeCountry: requestedLocations?.principalOfficeCountry,
43+
principalPhysicalLocationCountry: requestedLocations?.principalPhysicalLocationCountry,
44+
},
45+
requestTime: toISOString(requestTime?.seconds?.toString()),
46+
requestedExpiration: toISOString(requestedExpiration?.seconds?.toString()),
47+
approve: {
48+
approveTime: toISOString(approve.approveTime?.seconds?.toString()),
49+
expireTime: toISOString(approve.expireTime?.seconds?.toString()),
50+
invalidateTime: toISOString(approve.invalidateTime?.seconds?.toString()),
51+
signatureInfo: {
52+
signature: approve?.signatureInfo?.signature ? String.fromCharCode.apply(approve?.signatureInfo?.signature) : '',
53+
googlePublicKeyPem: approve?.signatureInfo?.googlePublicKeyPem,
54+
customerKmsKeyVersion: approve?.signatureInfo?.customerKmsKeyVersion,
55+
},
56+
autoApproved: approve?.autoApproved,
57+
},
58+
dismiss: {
59+
dismissTime: toISOString(dismiss.dismissTime?.seconds?.toString()),
60+
implicit: dismiss.implicit,
61+
},
62+
}
63+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { Service } from '@cloudgraph/sdk'
2+
import BaseService from '../base'
3+
import format from './format'
4+
import getData from './data'
5+
import mutation from './mutation'
6+
7+
export default class GcpAccessApproval extends BaseService implements Service {
8+
format = format.bind(this)
9+
10+
getData = getData.bind(this)
11+
12+
mutation = mutation
13+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export default `mutation($input: [AddgcpAccessApprovalInput!]!) {
2+
addgcpAccessApproval(input: $input, upsert: true) {
3+
numUids
4+
}
5+
}`;
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
type gcpAccessApprovalRequestedResourceProperties
2+
@generate(
3+
query: { get: false, query: true, aggregate: false }
4+
mutation: { add: false, delete: false }
5+
subscription: false
6+
) {
7+
excludesDescendants: Boolean @search
8+
}
9+
10+
type gcpAccessApprovalRequestedReason
11+
@generate(
12+
query: { get: false, query: true, aggregate: false }
13+
mutation: { add: false, delete: false }
14+
subscription: false
15+
) {
16+
type: String @search(by: [hash, regexp])
17+
detail: String @search(by: [hash, regexp])
18+
}
19+
20+
type gcpAccessApprovalRequestedLocations
21+
@generate(
22+
query: { get: false, query: true, aggregate: false }
23+
mutation: { add: false, delete: false }
24+
subscription: false
25+
) {
26+
principalOfficeCountry: String @search(by: [hash, regexp])
27+
principalPhysicalLocationCountry: String @search(by: [hash, regexp])
28+
}
29+
30+
type gcpAccessApprovalApproveSignatureInfo
31+
@generate(
32+
query: { get: false, query: true, aggregate: false }
33+
mutation: { add: false, delete: false }
34+
subscription: false
35+
) {
36+
signature: String @search(by: [hash, regexp])
37+
googlePublicKeyPem: String @search(by: [hash, regexp])
38+
customerKmsKeyVersion: String @search(by: [hash, regexp])
39+
}
40+
41+
type gcpAccessApprovalApprove
42+
@generate(
43+
query: { get: false, query: true, aggregate: false }
44+
mutation: { add: false, delete: false }
45+
subscription: false
46+
) {
47+
approveTime: String @search(by: [hash, regexp])
48+
expireTime: String @search(by: [hash, regexp])
49+
invalidateTime: String @search(by: [hash, regexp])
50+
signatureInfo: gcpAccessApprovalApproveSignatureInfo
51+
autoApproved: Boolean @search
52+
}
53+
54+
type gcpAccessApprovalDismiss
55+
@generate(
56+
query: { get: false, query: true, aggregate: false }
57+
mutation: { add: false, delete: false }
58+
subscription: false
59+
) {
60+
dismissTime: String @search(by: [hash, regexp])
61+
implicit: Boolean @search
62+
}
63+
64+
type gcpAccessApproval implements gcpBaseResource
65+
@generate(
66+
query: { get: true, query: true, aggregate: true }
67+
mutation: { add: true, delete: false }
68+
subscription: false
69+
)
70+
@key(fields: "id") {
71+
name: String @search(by: [hash, regexp])
72+
requestedResourceName: String @search(by: [hash, regexp])
73+
requestedResourceProperties: gcpAccessApprovalRequestedResourceProperties
74+
requestedReason: gcpAccessApprovalRequestedReason
75+
requestedLocations: gcpAccessApprovalRequestedLocations
76+
requestTime: String @search(by: [hash, regexp])
77+
requestedExpiration: String @search(by: [hash, regexp])
78+
approve: gcpAccessApprovalApprove
79+
dismiss: gcpAccessApprovalDismiss
80+
project: [gcpProject] @hasInverse(field: accessApprovals)
81+
}

0 commit comments

Comments
 (0)