Last active
September 4, 2021 20:38
-
-
Save itmayziii/25743011b013c9df7fca89a7aa987177 to your computer and use it in GitHub Desktop.
Terraform IAM Bindings GCP Service Agents
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"type": "module", | |
"private": true, | |
"author": "Tommy May III <[email protected]>", | |
"license": "MIT", | |
"dependencies": { | |
"node-fetch": "~3.0.0", | |
"node-html-parser": "~4.1.4" | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import nodeHTMLParser from 'node-html-parser' | |
import fetch from 'node-fetch' | |
const { parse } = nodeHTMLParser | |
const baseGCPURL = 'https://cloud.google.com' | |
const args = process.argv.slice(2) | |
const projectId = args[0] | |
if (!projectId) { | |
throw new Error('Project ID should be supplied to this script, "node service-agents.js \'${google_project.project.number}\'"') | |
} | |
fetch(`${baseGCPURL}/iam/docs/service-agents`) | |
.then(response => { | |
if (!response.ok) { | |
throw new Error(`Unexpected response ${response.statusText}, ${response.status}.`) | |
} | |
return response.text() | |
}) | |
.then(responseHTML => { | |
const html = parse(responseHTML) | |
const serviceAgentsTable = html.querySelector('#service-agents') | |
if (!serviceAgentsTable) { | |
throw new Error('Unable to find service agents table.') | |
} | |
const serviceAgentsTableBody = serviceAgentsTable.querySelector('.list') | |
if (!serviceAgentsTableBody) { | |
throw new Error('Unable to find service agents table body.') | |
} | |
serviceAgentsTableBody.removeWhitespace() | |
// Most service agents need to be prefixed with `service-` but certain ones do not, hence this exception list. | |
const exceptionRoles = ['roles/cloudbuild.builds.builder'] | |
serviceAgentsTableBody.childNodes.map(tableRow => { | |
const { name, domain, link, role } = extractDataFromRow(tableRow) | |
if (!name || !domain || !link || !role) return | |
const member = exceptionRoles.includes(role) | |
? `serviceAccount:${projectId}@${domain}` | |
: `serviceAccount:service-${projectId}@${domain}` | |
console.log(` | |
binding { | |
/* | |
${name} | |
${link} | |
*/ | |
role = "${role}" | |
members = ["${member}"] | |
} | |
`.trim()) | |
}) | |
}) | |
.catch(console.error) | |
function extractDataFromRow (row) { | |
const name = row.childNodes[0].text.trim() | |
const domain = row.childNodes[1].text.trim() | |
if (row.childNodes[2].text.trim().toLowerCase() === 'none') { | |
return { name, domain, link: null, role: null } | |
} | |
const anchor = row.childNodes[2].querySelector('a') | |
if (!anchor) { | |
throw new Error(`Unable to find documentation link for ${name}`) | |
} | |
const link = anchor.getAttribute('href').trim() | |
if (!link) { | |
throw new Error(`Empty documentation link for ${name}`) | |
} | |
const code = row.childNodes[2].querySelector('code') | |
if (!code) { | |
throw new Error(`Unable to find documentation link for ${name}`) | |
} | |
const role = code.text.trim() | |
if (!role) { | |
throw new Error(`Empty role for ${name}`) | |
} | |
return { name, domain, link: `${baseGCPURL}${link}`, role } | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment