Skip to content

Commit 1876d86

Browse files
feat(serviceAccount): GCP service account shell script [ENG-44162] (#1)
* pushing shell script and readme [ENG-44162] * chore(documentation): update README.md * correct readme file [ENG-44162] * delete tf files [ENG-44162] * chore(documentation): update README.md * get rid of for user access review from readme [ENG-44162] * chore(documentation): update README.md * revert readme changes [ENG-44162] * delete github actions [ENG-44162] * little changes on readme [ENG-44162] * remove codeowners [ENG-44162] * add drata_role_name variable [ENG-44162] * readme file changes [ENG-44162] --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
1 parent 03c31bd commit 1876d86

File tree

12 files changed

+187
-220
lines changed

12 files changed

+187
-220
lines changed

.github/workflows/documentation-generator.yml

Lines changed: 0 additions & 51 deletions
This file was deleted.

.github/workflows/linter.yml

Lines changed: 0 additions & 37 deletions
This file was deleted.

.gitignore

Lines changed: 0 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +0,0 @@
1-
# Local .terraform directories
2-
**/.terraform/*
3-
4-
# lockfile
5-
.terraform.lock.hcl
6-
7-
# .tfstate files
8-
*.tfstate
9-
*.tfstate.*
10-
11-
# Crash log files
12-
crash.log
13-
crash.*.log
14-
15-
# Exclude all .tfvars files, which are likely to contain sensitive data, such as
16-
# password, private keys, and other secrets. These should not be part of version
17-
# control as they are data points which are potentially sensitive and subject
18-
# to change depending on the environment.
19-
*.tfvars
20-
*.tfvars.json
21-
22-
# Ignore override files as they are usually used to override resources locally and so
23-
# are not checked in
24-
override.tf
25-
override.tf.json
26-
*_override.tf
27-
*_override.tf.json
28-
29-
# Include override files you do wish to add to version control using negated pattern
30-
# !example_override.tf
31-
32-
# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan
33-
# example: *tfplan*
34-
35-
# Ignore CLI configuration files
36-
.terraformrc
37-
terraform.rc

.terraform-docs.yml

Lines changed: 0 additions & 6 deletions
This file was deleted.

.tflint.hcl

Lines changed: 0 additions & 18 deletions
This file was deleted.

CODEOWNERS

Lines changed: 0 additions & 3 deletions
This file was deleted.

README.md

Lines changed: 14 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,18 @@
1-
# Terraform Module Template
1+
# gcp-shell-drata-setup
22

3-
**Next steps**
4-
1. Update the top section of this file to tell people about this module.
5-
2. Update `versions.tf` to include the required providers for the module.
6-
3. Add resources and variables to solve the problem.
7-
4. Add outputs for relevant details the consumer may want
8-
5. Add example uses to the bottom of this file
9-
6. Update the generated portion of this file using `terraform-docs .`
3+
Shell script to create the Drata Read Only service account.
104

5+
## Usage
116

12-
<!-- BEGIN_TF_DOCS -->
13-
## Requirements
7+
The following steps demonstrate how to connect GCP in Drata when using this script.
148

15-
| Name | Version |
16-
|------|---------|
17-
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 0.15 |
18-
19-
## Providers
20-
21-
| Name | Version |
22-
|------|---------|
23-
| <a name="provider_null"></a> [null](#provider\_null) | n/a |
24-
25-
## Modules
26-
27-
No modules.
28-
29-
## Resources
30-
31-
| Name | Type |
32-
|------|------|
33-
| [null_resource.nope](https://registry.terraform.io/providers/hashicorp/null/latest/docs/resources/resource) | resource |
34-
35-
## Inputs
36-
37-
No inputs.
38-
39-
## Outputs
40-
41-
| Name | Description |
42-
|------|-------------|
43-
| <a name="output_nope"></a> [nope](#output\_nope) | TODO: Remove this and add your own outputs |
44-
| <a name="output_true"></a> [true](#output\_true) | n/a |
45-
<!-- END_TF_DOCS -->
46-
47-
## Examples
48-
49-
**TODO:** Add examples here
9+
1. Navigate to the Cloud Shell terminal in your GCP account using the following link: [https://console.cloud.google.com/welcome?cloudshell=true](https://console.cloud.google.com/welcome?cloudshell=true).
10+
2. Click the `Open editor` button at the top of the terminal to navigate to your editor.
11+
3. Create a file with `.sh` extension in the root directory i.e. `drata.sh`.
12+
4. Copy the content of the `gcp-drata-script.sh` from this project and paste it in the newly created file.
13+
5. Click the `Open terminal` button at the top of the editor to navigate back to your terminal, run the following commands.
14+
1. `chmod +x drata.sh` to give it execution permissions.
15+
2. `./drata.sh` to run the script.
16+
6. After the process finishes, navigate back to your editor and download the `drata-key-file.json` file.
17+
7. In the Drata app, go to the GCP connection drawer and select Upload File to upload the `drata-key-file.json` file.
18+
8. Select the `Save & Test Connection` button.

gcp-drata-script.sh

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
# Script to create the drata custom roles and service account
2+
# The project to store the resources is the default per account
3+
4+
set -e
5+
6+
# Logging utilities
7+
prefix="[ Drata ]"
8+
9+
# Resource names
10+
drata_role_name="DrataReadOnly"
11+
serviceAccountId="${drata_role_name,,}"
12+
projectRole="${drata_role_name}ProjectRole"
13+
organizationRole="${drata_role_name}OrganizationalRole"
14+
15+
# check google cloud shell
16+
if ! command -v gcloud &>/dev/null; then
17+
printf "${prefix} [ERROR] Please run this script within a Google Cloud Console Shell,\n consult https://cloud.google.com/shell/docs/run-gcloud-commands for help\n"
18+
exit
19+
fi
20+
21+
printf "${prefix} Getting project info...🔎 \n\n"
22+
23+
# get account's default project
24+
projectId=$(
25+
gcloud config get-value project
26+
)
27+
if [ -z "${projectId}" ]
28+
then
29+
printf "${prefix} The default project is unset, please check the configuration...❌ \n\n"
30+
exit;
31+
fi
32+
33+
# validate if the projectId is valid
34+
# get project name
35+
projectName=$(
36+
gcloud projects list --format="value(name)" --filter="id=$projectId"
37+
)
38+
39+
# if, by mistake, the user set himself an invalid project, it won't be found
40+
if [ -z "${projectName}" ]
41+
then
42+
printf "${prefix} Project '${projectId}' is not found, please check the configuration...❌ \n\n"
43+
exit;
44+
fi
45+
46+
printf "\n${prefix} Enabling services...🛜 \n"
47+
gcloud services enable compute.googleapis.com cloudresourcemanager.googleapis.com admin.googleapis.com \
48+
sqladmin.googleapis.com monitoring.googleapis.com --no-user-output-enabled
49+
printf "${prefix} Necessary services enabled 🚀 \n\n"
50+
51+
serviceAccountEmail="${serviceAccountId}@${projectId}.iam.gserviceaccount.com";
52+
# get ancestors of the project
53+
projectAncestorsInfo=$(gcloud projects get-ancestors $projectId --format='value[terminator="~",separator=","](type,id)')
54+
# convert projectAncestorsInfo to array below
55+
IFS='~'; read -r -a ancestorsArray <<< "$projectAncestorsInfo"
56+
57+
# iterate ancestors to get the organization
58+
for ancestor in ${ancestorsArray[@]}; do
59+
IFS=','; read -r -a ancestorValues <<< "$ancestor";
60+
type=${ancestorValues[0]};
61+
if [ $type == "organization" ]; then
62+
organizationId=${ancestorValues[1]};
63+
fi
64+
done
65+
66+
organizationName='No organization';
67+
if [ -n "$organizationId" ]; then
68+
# get organization's name
69+
organizationName=$(
70+
gcloud organizations list --format="value(displayName)" --filter="name=organizations/$organizationId"
71+
)
72+
fi
73+
74+
printf "${prefix} Creating resources at ${organizationName}/${projectName}...🚀 \n"
75+
76+
# *****************************
77+
# START CREATING RESOURCES ==>
78+
# *****************************
79+
80+
# ===========================
81+
# Custom Project Role
82+
# ===========================
83+
printf "\n${prefix} Checking custom role...\n";
84+
# Verify if the role exists already
85+
projectRoleInfo=$(
86+
gcloud iam roles list --show-deleted --project=$projectId --filter="name=projects/${projectId}/roles/${projectRole}" --format="value[separator=','](name,deleted)"
87+
);
88+
if [ -z "${projectRoleInfo}" ]
89+
then
90+
gcloud iam roles create $projectRole --project=$projectId --title="Drata Read-Only Project Role" --description="Service Account for Drata Autopilot to get read access to all project resources" --stage="GA" --no-user-output-enabled;
91+
else
92+
# check if the role is on deleted state
93+
IFS=','; read -r -a projectRoleArray <<< "$projectRoleInfo"
94+
isRoleDeleted=${projectRoleArray[1]};
95+
if [ -n "${isRoleDeleted}" ]
96+
then
97+
printf "${prefix} The role was deleted before, undeleting '${projectRole}' custom role to be available now...\n";
98+
gcloud iam roles undelete $projectRole --project=$projectId --no-user-output-enabled
99+
fi
100+
fi
101+
printf "${prefix} '${projectRole}' custom role has been created 🚀\n";
102+
103+
# Update permissions and stage
104+
gcloud iam roles update $projectRole --project=$projectId --permissions="\
105+
storage.buckets.get,\
106+
storage.buckets.getIamPolicy" --no-user-output-enabled --stage=GA
107+
108+
# ===========================
109+
# Custom Organization Role
110+
# ===========================
111+
printf "\n${prefix} Checking organization role...\n";
112+
# Verify if the role exists previously
113+
organizationRoleInfo=$(
114+
gcloud iam roles list --show-deleted --organization=$organizationId --filter="name=organizations/${organizationId}/roles/${organizationRole}" --format="value[separator=','](name,deleted)"
115+
);
116+
if [ -z "${organizationRoleInfo}" ]
117+
then
118+
gcloud iam roles create $organizationRole --organization=$organizationId --title="Drata Read-Only Organizational Role" --description="Service Account with read-only access for Drata Autopilot to get organizational IAM data." --stage="GA" --no-user-output-enabled
119+
else
120+
# check if the role is on deleted state
121+
IFS=','; read -r -a organizationRoleArray <<< "$organizationRoleInfo"
122+
isRoleDeleted=${organizationRoleArray[1]};
123+
if [ -n "${isRoleDeleted}" ]
124+
then
125+
printf "${prefix} The role was deleted before, undeleting '${organizationRole}' custom role to be available now...\n";
126+
gcloud iam roles undelete $organizationRole --organization=$organizationId --no-user-output-enabled
127+
fi
128+
fi
129+
printf "${prefix} '${organizationRole}' organization role has been created 🚀\n";
130+
131+
# Update permissions and stage
132+
gcloud iam roles update $organizationRole --organization=$organizationId --permissions="\
133+
resourcemanager.organizations.getIamPolicy,\
134+
storage.buckets.get,\
135+
storage.buckets.getIamPolicy" --no-user-output-enabled
136+
137+
# ===========================
138+
# Service Account
139+
# ===========================
140+
printf "\n${prefix} Checking service account...\n";
141+
# Check if the service account already exists
142+
serviceAccountInfo=$(
143+
gcloud iam service-accounts list --filter="email=${serviceAccountEmail}" --format="value[separator=','](email,projectId)"
144+
)
145+
if [ -z "$serviceAccountInfo" ]
146+
then
147+
gcloud iam service-accounts create ${serviceAccountId} --project="$projectId" --display-name="${serviceAccountId}" --description="Service Account with read-only access for Drata Autopilot" --no-user-output-enabled;
148+
else
149+
gcloud iam service-accounts update ${serviceAccountEmail} --project="$projectId" --display-name="${serviceAccountId}" --description="Service Account with read-only access for Drata Autopilot" --no-user-output-enabled;
150+
fi
151+
printf "${prefix} '${serviceAccountId}' service account has been created 🚀\n";
152+
# Create json key file
153+
printf "\n${prefix} Generating json key file...\n";
154+
(gcloud iam service-accounts keys create ./drata-key-file.json --iam-account=${serviceAccountEmail} --project="$projectId" --no-user-output-enabled &&
155+
printf "${prefix} Key file has been generated 🚀\n\n";)\
156+
|| printf "${prefix} Expected error, Please delete a key from the service account and run this script again. A max of 10 keys is supported per service account ❌\n\n"
157+
158+
# ===========================
159+
# Assignments
160+
# ===========================
161+
# Assing project custom role
162+
printf "${prefix} Assigning project custom role to service account...\n";
163+
gcloud projects add-iam-policy-binding $projectId --member="serviceAccount:${serviceAccountEmail}" --role="projects/${projectId}/roles/${projectRole}" --no-user-output-enabled
164+
# Assing organization custom role
165+
printf "\n${prefix} Assigning organization custom role to service account...\n";
166+
gcloud organizations add-iam-policy-binding $organizationId --member="serviceAccount:${serviceAccountEmail}" --role="organizations/${organizationId}/roles/${organizationRole}" --no-user-output-enabled
167+
# Assing viewer/role
168+
printf "\n${prefix} Assigning viewer/role to service account...\n";
169+
gcloud projects add-iam-policy-binding $projectId --member="serviceAccount:${serviceAccountEmail}" --role="roles/viewer" --no-user-output-enabled
170+
171+
# ===========================
172+
printf "\n${prefix} Done! Service Account '${serviceAccountId}' has been granted ✅\n"
173+
# ===========================

0 commit comments

Comments
 (0)