From 6aa94421066f819f7f5f28f20ce17e1a0edb2f72 Mon Sep 17 00:00:00 2001 From: Lucian Hymer Date: Wed, 24 Jul 2024 09:53:53 -0600 Subject: [PATCH] feat(infra): using infra-libs repo --- infra/aws/index.ts | 54 +++++++++------- infra/aws/secrets.ts | 101 ----------------------------- infra/package-lock.json | 137 ++++++++++++++++++++++++++-------------- infra/package.json | 3 +- 4 files changed, 122 insertions(+), 173 deletions(-) delete mode 100644 infra/aws/secrets.ts diff --git a/infra/aws/index.ts b/infra/aws/index.ts index 768aa6e..d88e456 100644 --- a/infra/aws/index.ts +++ b/infra/aws/index.ts @@ -2,17 +2,10 @@ import * as pulumi from "@pulumi/pulumi"; import * as aws from "@pulumi/aws"; import * as op from "@1password/op-js"; -import { - getEnvironmentVars, - syncSecretsAndGetRefs, - sortByName, -} from "./secrets"; +import { secretsManager } from "infra-libs"; const stack = pulumi.getStack(); -export const SCROLL_SECRETS_ARN = op.read.parse( - `op://DevOps/passport-scroll-badge-service-${stack}-env/ci/SCROLL_SECRETS_ARN` -); export const ROUTE53_DOMAIN = op.read.parse( `op://DevOps/passport-scroll-badge-service-${stack}-env/ci/ROUTE53_DOMAIN` ); @@ -43,6 +36,14 @@ const logsRetention = Object({ production: 30, }); +const scrollSecret = new aws.secretsmanager.Secret("scroll-secrets", { + name: `scroll-secrets`, + description: "Scroll Badge Service Secrets", + tags: { + ...defaultTags, + }, +}); + const coreInfraStack = new pulumi.StackReference(`gitcoin/core-infra/${stack}`); const snsAlertsTopicArn = coreInfraStack.getOutput("snsAlertsTopicArn"); const passportInfraStack = new pulumi.StackReference( @@ -66,23 +67,28 @@ const passwordManagerParams = { section: "service", }; -const scrollBadgeServiceSecretReferences = syncSecretsAndGetRefs({ - ...passwordManagerParams, - targetSecretArn: SCROLL_SECRETS_ARN, -}); - -const secrets = [ - ...scrollBadgeServiceSecretReferences, +const scrollBadgeServiceSecretReferences = secretsManager.syncSecretsAndGetRefs( { - name: "SCROLL_BADGE_ATTESTATION_SIGNER_PRIVATE_KEY", - valueFrom: `${VC_SECRETS_ARN}:SCROLL_BADGE_ATTESTATION_SIGNER_PRIVATE_KEY::`, - }, -].sort(sortByName); + ...passwordManagerParams, + secretVersionName: "scroll-badge-service-secret-version", + targetSecret: scrollSecret, + } +); + +const secrets = scrollBadgeServiceSecretReferences.apply((refs) => + [ + ...refs, + { + name: "SCROLL_BADGE_ATTESTATION_SIGNER_PRIVATE_KEY", + valueFrom: `${VC_SECRETS_ARN}:SCROLL_BADGE_ATTESTATION_SIGNER_PRIVATE_KEY::`, + }, + ].sort(secretsManager.sortByName) +); -const environment = getEnvironmentVars(passwordManagerParams); +const environment = secretsManager.getEnvironmentVars(passwordManagerParams); const serviceRole = new aws.iam.Role("scroll-badge-ecs-role", { - assumeRolePolicy: JSON.stringify({ + assumeRolePolicy: pulumi.jsonStringify({ Version: "2012-10-17", Statement: [ { @@ -98,13 +104,13 @@ const serviceRole = new aws.iam.Role("scroll-badge-ecs-role", { inlinePolicies: [ { name: "allow_iam_secrets_access", - policy: JSON.stringify({ + policy: pulumi.jsonStringify({ Version: "2012-10-17", Statement: [ { Action: ["secretsmanager:GetSecretValue"], Effect: "Allow", - Resource: [SCROLL_SECRETS_ARN, VC_SECRETS_ARN], + Resource: [scrollSecret.arn, VC_SECRETS_ARN], }, ], }), @@ -239,7 +245,7 @@ const albListenerRule = new aws.lb.ListenerRule(`scroll-badge-service-https`, { const service_data = DOCKER_SCROLL_SERVICE_IMAGE.apply((drk_image) => { const taskDefinition = new aws.ecs.TaskDefinition(`scroll-badge-service-td`, { family: `scroll-badge-service-td`, - containerDefinitions: JSON.stringify([ + containerDefinitions: pulumi.jsonStringify([ { name: "scroll-badge-service", image: drk_image, diff --git a/infra/aws/secrets.ts b/infra/aws/secrets.ts deleted file mode 100644 index 7853931..0000000 --- a/infra/aws/secrets.ts +++ /dev/null @@ -1,101 +0,0 @@ -import { Item, item, validateCli } from "@1password/op-js"; -import * as aws from "@pulumi/aws"; -import * as pulumi from "@pulumi/pulumi"; - -type GetPasswordManagerDataParams = { - vault: string; - repo: string; - env: string; - section?: string; - type: "secrets" | "env"; -}; - -type GetEnvironmentVarsParams = Omit; - -type SyncSecretsAndGetRefsParams = GetEnvironmentVarsParams & { - targetSecretArn: string; -}; - -type EnvironmentVar = { name: string; value: string }; -type SecretRef = { name: string; valueFrom: string }; - -// Given a 1P definition and a target secret ARN, sync the secrets to the target secret -// object in AWS Secrets Manager and return the references to those secret values -export const syncSecretsAndGetRefs = ( - params: SyncSecretsAndGetRefsParams -): SecretRef[] => { - const { targetSecretArn, ...passwordManagerParams } = params; - - const secretDefinitions = getPasswordManagerData({ - ...passwordManagerParams, - type: "secrets", - }); - - const secretString = JSON.stringify( - secretDefinitions.reduce((acc, { name, value }) => { - acc[name] = value; - return acc; - }, {} as Record) - ); - - new aws.secretsmanager.SecretVersion( - `${targetSecretArn.split(":").slice(-1)}-secret-version`, - { - secretId: targetSecretArn, - secretString, - versionStages: ["AWSCURRENT"], - } - ); - - return secretDefinitions.map(({ name }) => ({ - name, - valueFrom: `${targetSecretArn}:${name}::`, - })); -}; - -// Given a 1P definition, return the environment variables -export const getEnvironmentVars = ( - params: GetEnvironmentVarsParams -): EnvironmentVar[] => { - return getPasswordManagerData({ ...params, type: "env" }); -}; - -const password_manager_ci_validated = false; - -const getPasswordManagerData = ({ - vault, - repo, - env, - type, - section, -}: GetPasswordManagerDataParams): EnvironmentVar[] => { - password_manager_ci_validated || validateCli(); - - const noteName = `${repo}-${env}-${type}`; - - const envNote = item.get(noteName, { vault }) as Item; - - const fields = - (section - ? envNote.fields?.filter((field) => field.section?.label === section) - : envNote.fields) || []; - - if (!fields.length) { - throw new Error( - `No data found for ${vault}/${repo}-${env}-${type}${ - section ? `/${section}` : "" - }` - ); - } - - return fields - .map(({ label, value }) => ({ name: label, value })) - .sort(sortByName); -}; - -// Pulumi sorts alphabetically by name, so we want to match so that -// the diff doesn't falsely show differences because of the order. -// This is used above to pre-sort. But if you add to any of these -// arrays, you'll want to sort the final array as well -export const sortByName = (a: { name: string }, b: { name: string }) => - a.name.localeCompare(b.name); diff --git a/infra/package-lock.json b/infra/package-lock.json index c3ae0b5..44a02e5 100644 --- a/infra/package-lock.json +++ b/infra/package-lock.json @@ -9,7 +9,8 @@ "@1password/op-js": "^0.1.13", "@pulumi/aws": "^6.0.2", "@pulumi/awsx": "^1.0.5", - "@pulumi/pulumi": "^3.113.0" + "@pulumi/pulumi": "^3.113.0", + "infra-libs": "github:passportxyz/infra-libs#semver:^1.0.0" }, "devDependencies": { "@types/node": "^18", @@ -315,11 +316,10 @@ "node": ">=8.0.0" } }, - "node_modules/@opentelemetry/api-metrics": { - "version": "0.32.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api-metrics/-/api-metrics-0.32.0.tgz", - "integrity": "sha512-g1WLhpG8B6iuDyZJFRGsR+JKyZ94m5LEmY2f+duEJ9Xb4XRlLHrZvh6G34OH6GJ8iDHxfHb/sWjJ1ZpkI9yGMQ==", - "deprecated": "Please use @opentelemetry/api >= 1.3.0", + "node_modules/@opentelemetry/api-logs": { + "version": "0.52.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.52.1.tgz", + "integrity": "sha512-qnSqB2DQ9TPP96dl8cDubDvrUyWc0/sK81xHTK8eSUspzDM3bsewX903qclQFvVhgStjRWdC5bLb3kQqMkfV5A==", "dependencies": { "@opentelemetry/api": "^1.0.0" }, @@ -370,44 +370,37 @@ } }, "node_modules/@opentelemetry/instrumentation": { - "version": "0.32.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.32.0.tgz", - "integrity": "sha512-y6ADjHpkUz/v1nkyyYjsQa/zorhX+0qVGpFvXMcbjU4sHnBnC02c6wcc93sIgZfiQClIWo45TGku1KQxJ5UUbQ==", - "dependencies": { - "@opentelemetry/api-metrics": "0.32.0", - "require-in-the-middle": "^5.0.3", - "semver": "^7.3.2", + "version": "0.52.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.52.1.tgz", + "integrity": "sha512-uXJbYU/5/MBHjMp1FqrILLRuiJCs3Ofk0MeRDk8g1S1gD47U8X3JnSwcMO1rtRo1x1a7zKaQHaoYu49p/4eSKw==", + "dependencies": { + "@opentelemetry/api-logs": "0.52.1", + "@types/shimmer": "^1.0.2", + "import-in-the-middle": "^1.8.1", + "require-in-the-middle": "^7.1.1", + "semver": "^7.5.2", "shimmer": "^1.2.1" }, "engines": { "node": ">=14" }, "peerDependencies": { - "@opentelemetry/api": "^1.0.0" + "@opentelemetry/api": "^1.3.0" } }, "node_modules/@opentelemetry/instrumentation-grpc": { - "version": "0.32.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-grpc/-/instrumentation-grpc-0.32.0.tgz", - "integrity": "sha512-Az6wdkPx/Mi26lT9LKFV6GhCA9prwQFPz5eCNSExTnSP49YhQ7XCjzPd2POPeLKt84ICitrBMdE1mj0zbPdLAQ==", + "version": "0.52.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-grpc/-/instrumentation-grpc-0.52.1.tgz", + "integrity": "sha512-EdSDiDSAO+XRXk/ZN128qQpBo1I51+Uay/LUPcPQhSRGf7fBPIEUBeOLQiItguGsug5MGOYjql2w/1wCQF3fdQ==", "dependencies": { - "@opentelemetry/api-metrics": "0.32.0", - "@opentelemetry/instrumentation": "0.32.0", - "@opentelemetry/semantic-conventions": "1.6.0" + "@opentelemetry/instrumentation": "0.52.1", + "@opentelemetry/semantic-conventions": "1.25.1" }, "engines": { "node": ">=14" }, "peerDependencies": { - "@opentelemetry/api": "^1.0.0" - } - }, - "node_modules/@opentelemetry/instrumentation-grpc/node_modules/@opentelemetry/semantic-conventions": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.6.0.tgz", - "integrity": "sha512-aPfcBeLErM/PPiAuAbNFLN5sNbZLc3KZlar27uohllN8Zs6jJbHyJU1y7cMA6W/zuq+thkaG8mujiS+3iD/FWQ==", - "engines": { - "node": ">=14" + "@opentelemetry/api": "^1.3.0" } }, "node_modules/@opentelemetry/propagator-b3": { @@ -560,9 +553,9 @@ "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" }, "node_modules/@pulumi/aws": { - "version": "6.42.0", - "resolved": "https://registry.npmjs.org/@pulumi/aws/-/aws-6.42.0.tgz", - "integrity": "sha512-HNsUVlm6x1bcrNN/bDm3F/tAk55sWJF+oaWNdq2WSVHzzGGrWVFnScyjoGZlfSDaufWQ/uKjHaNDn2nZVg/VuA==", + "version": "6.45.2", + "resolved": "https://registry.npmjs.org/@pulumi/aws/-/aws-6.45.2.tgz", + "integrity": "sha512-SH1/0dcPtCn6Eiqp+CzTUE8lko5JioTSqW/S7c3t3xlpzPbyMo69NUFuUKMGH7aLAalBAKW5ImiDOiRpY3z0DQ==", "dependencies": { "@pulumi/pulumi": "^3.0.0", "builtin-modules": "3.0.0", @@ -616,21 +609,21 @@ } }, "node_modules/@pulumi/pulumi": { - "version": "3.121.0", - "resolved": "https://registry.npmjs.org/@pulumi/pulumi/-/pulumi-3.121.0.tgz", - "integrity": "sha512-fv9sY1e7nPeGpvlHIMZcErHeZAsbdqOi0Jcb1oxi0NvTU3jy1EZa70q+JdE0dmqYlr43HaSL8SU5+G0/S08wGA==", + "version": "3.126.0", + "resolved": "https://registry.npmjs.org/@pulumi/pulumi/-/pulumi-3.126.0.tgz", + "integrity": "sha512-NPYGHeavLh8Y2quOcx0KLMAM0WWES5RoJ9iywp953iL7hSqv1W77/GjvYuhj5jdm2O9Ty2AjYs74zpfeYzkOoQ==", "dependencies": { "@grpc/grpc-js": "^1.10.1", "@logdna/tail-file": "^2.0.6", "@npmcli/arborist": "^7.3.1", - "@opentelemetry/api": "^1.2.0", - "@opentelemetry/exporter-zipkin": "^1.6.0", - "@opentelemetry/instrumentation": "^0.32.0", - "@opentelemetry/instrumentation-grpc": "^0.32.0", - "@opentelemetry/resources": "^1.6.0", - "@opentelemetry/sdk-trace-base": "^1.6.0", - "@opentelemetry/sdk-trace-node": "^1.6.0", - "@opentelemetry/semantic-conventions": "^1.6.0", + "@opentelemetry/api": "^1.9", + "@opentelemetry/exporter-zipkin": "^1.25", + "@opentelemetry/instrumentation": "^0.52", + "@opentelemetry/instrumentation-grpc": "^0.52", + "@opentelemetry/resources": "^1.25", + "@opentelemetry/sdk-trace-base": "^1.25", + "@opentelemetry/sdk-trace-node": "^1.25", + "@opentelemetry/semantic-conventions": "^1.25", "@pulumi/query": "^0.3.0", "@types/google-protobuf": "^3.15.5", "@types/semver": "^7.5.6", @@ -837,6 +830,11 @@ "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==" }, + "node_modules/@types/shimmer": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@types/shimmer/-/shimmer-1.2.0.tgz", + "integrity": "sha512-UE7oxhQLLd9gub6JKIAhDq06T0F6FnztwMNRvYgjeQSBeMc1ZG/tA47EwfduvkuQS8apbkM/lpLpWsaCeYsXVg==" + }, "node_modules/@types/tmp": { "version": "0.2.6", "resolved": "https://registry.npmjs.org/@types/tmp/-/tmp-0.2.6.tgz", @@ -850,6 +848,25 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/acorn": { + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-attributes": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", + "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", + "peerDependencies": { + "acorn": "^8" + } + }, "node_modules/agent-base": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", @@ -1155,6 +1172,11 @@ "node": ">=10" } }, + "node_modules/cjs-module-lexer": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.3.1.tgz", + "integrity": "sha512-a3KdPAANPbNE4ZUv9h6LckSl9zLsYOP4MBmhIPkRaeyybt+r4UghLvq+xw/YwUcC1gqylCkL4rdVs3Lwupjm4Q==" + }, "node_modules/clean-stack": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", @@ -2096,6 +2118,17 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/import-in-the-middle": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/import-in-the-middle/-/import-in-the-middle-1.10.0.tgz", + "integrity": "sha512-Z1jumVdF2GwnnYfM0a/y2ts7mZbwFMgt5rRuVmLgobgahC6iKgN5MBuXjzfTIOUpq5LSU10vJIPpVKe0X89fIw==", + "dependencies": { + "acorn": "^8.8.2", + "acorn-import-attributes": "^1.9.5", + "cjs-module-lexer": "^1.2.2", + "module-details-from-path": "^1.0.3" + } + }, "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -2122,6 +2155,16 @@ "wrappy": "1" } }, + "node_modules/infra-libs": { + "version": "1.0.0", + "resolved": "git+ssh://git@github.com/passportxyz/infra-libs.git#f3072dc8d547529c5cb7200c02178046d2d47e0e", + "license": "ISC", + "dependencies": { + "@1password/op-js": "^0.1.13", + "@pulumi/aws": "^6.45.0", + "@pulumi/pulumi": "^3.126.0" + } + }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -3502,16 +3545,16 @@ } }, "node_modules/require-in-the-middle": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-5.2.0.tgz", - "integrity": "sha512-efCx3b+0Z69/LGJmm9Yvi4cqEdxnoGnxYxGxBghkkTTFeXRtTCmmhO0AnAfHz59k957uTSuy8WaHqOs8wbYUWg==", + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-7.3.0.tgz", + "integrity": "sha512-nQFEv9gRw6SJAwWD2LrL0NmQvAcO7FBwJbwmr2ttPAacfy0xuiOjE5zt+zM4xDyuyvUaxBi/9gb2SoCyNEVJcw==", "dependencies": { "debug": "^4.1.1", "module-details-from-path": "^1.0.3", "resolve": "^1.22.1" }, "engines": { - "node": ">=6" + "node": ">=8.6.0" } }, "node_modules/resolve": { diff --git a/infra/package.json b/infra/package.json index 7f66a5f..d7ace76 100644 --- a/infra/package.json +++ b/infra/package.json @@ -8,6 +8,7 @@ "@1password/op-js": "^0.1.13", "@pulumi/aws": "^6.0.2", "@pulumi/awsx": "^1.0.5", - "@pulumi/pulumi": "^3.113.0" + "@pulumi/pulumi": "^3.113.0", + "infra-libs": "github:passportxyz/infra-libs#semver:^1.0.0" } }