forked from cerc-io/snowballtools-base
Implement functionality to encrypt environment variables (#48)
Part of https://www.notion.so/Support-encrypted-config-for-deploy-laconic-com-18aa6b22d4728099bc64fc7a310b530d Co-authored-by: IshaVenikar <ishavenikar7@gmail.com> Reviewed-on: cerc-io/snowballtools-base#48
This commit is contained in:
parent
17640d3133
commit
534871a7ae
@ -27,6 +27,7 @@
|
|||||||
"nanoid": "3",
|
"nanoid": "3",
|
||||||
"nanoid-dictionary": "^5.0.0-beta.1",
|
"nanoid-dictionary": "^5.0.0-beta.1",
|
||||||
"octokit": "^3.1.2",
|
"octokit": "^3.1.2",
|
||||||
|
"openpgp": "^6.0.1",
|
||||||
"reflect-metadata": "^0.2.1",
|
"reflect-metadata": "^0.2.1",
|
||||||
"semver": "^7.6.0",
|
"semver": "^7.6.0",
|
||||||
"toml": "^3.0.0",
|
"toml": "^3.0.0",
|
||||||
|
@ -15,6 +15,9 @@ export class Deployer {
|
|||||||
@Column('varchar')
|
@Column('varchar')
|
||||||
baseDomain!: string;
|
baseDomain!: string;
|
||||||
|
|
||||||
|
@Column('varchar', { nullable: true})
|
||||||
|
publicKey!: string | null;
|
||||||
|
|
||||||
@Column('varchar', { nullable: true })
|
@Column('varchar', { nullable: true })
|
||||||
minimumPayment!: string | null;
|
minimumPayment!: string | null;
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import { DateTime } from 'luxon';
|
|||||||
import { Octokit } from 'octokit';
|
import { Octokit } from 'octokit';
|
||||||
import { inc as semverInc } from 'semver';
|
import { inc as semverInc } from 'semver';
|
||||||
import { DeepPartial } from 'typeorm';
|
import { DeepPartial } from 'typeorm';
|
||||||
|
import * as openpgp from 'openpgp';
|
||||||
|
|
||||||
import { Account, DEFAULT_GAS_ESTIMATION_MULTIPLIER, Registry as LaconicRegistry, getGasPrice, parseGasAndFees } from '@cerc-io/registry-sdk';
|
import { Account, DEFAULT_GAS_ESTIMATION_MULTIPLIER, Registry as LaconicRegistry, getGasPrice, parseGasAndFees } from '@cerc-io/registry-sdk';
|
||||||
import { DeliverTxResponse, IndexedTx } from '@cosmjs/stargate';
|
import { DeliverTxResponse, IndexedTx } from '@cosmjs/stargate';
|
||||||
@ -246,8 +247,11 @@ export class Registry {
|
|||||||
repository: string,
|
repository: string,
|
||||||
auctionId?: string | null,
|
auctionId?: string | null,
|
||||||
lrn: string,
|
lrn: string,
|
||||||
|
apiUrl: string,
|
||||||
environmentVariables: { [key: string]: string },
|
environmentVariables: { [key: string]: string },
|
||||||
dns: string,
|
dns: string,
|
||||||
|
requesterAddress: string,
|
||||||
|
publicKey: string,
|
||||||
payment?: string | null
|
payment?: string | null
|
||||||
}): Promise<{
|
}): Promise<{
|
||||||
applicationDeploymentRequestId: string;
|
applicationDeploymentRequestId: string;
|
||||||
@ -261,6 +265,13 @@ export class Registry {
|
|||||||
throw new Error(`No record found for ${lrn}`);
|
throw new Error(`No record found for ${lrn}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const hash = await this.generateConfigHash(
|
||||||
|
data.environmentVariables,
|
||||||
|
data.requesterAddress,
|
||||||
|
data.publicKey,
|
||||||
|
data.apiUrl,
|
||||||
|
);
|
||||||
|
|
||||||
// Create record of type ApplicationDeploymentRequest and publish
|
// Create record of type ApplicationDeploymentRequest and publish
|
||||||
const applicationDeploymentRequest = {
|
const applicationDeploymentRequest = {
|
||||||
type: APP_DEPLOYMENT_REQUEST_TYPE,
|
type: APP_DEPLOYMENT_REQUEST_TYPE,
|
||||||
@ -271,7 +282,7 @@ export class Registry {
|
|||||||
|
|
||||||
// https://git.vdb.to/cerc-io/laconic-registry-cli/commit/129019105dfb93bebcea02fde0ed64d0f8e5983b
|
// https://git.vdb.to/cerc-io/laconic-registry-cli/commit/129019105dfb93bebcea02fde0ed64d0f8e5983b
|
||||||
config: JSON.stringify({
|
config: JSON.stringify({
|
||||||
env: data.environmentVariables
|
ref: hash,
|
||||||
}),
|
}),
|
||||||
meta: JSON.stringify({
|
meta: JSON.stringify({
|
||||||
note: `Added by Snowball @ ${DateTime.utc().toFormat(
|
note: `Added by Snowball @ ${DateTime.utc().toFormat(
|
||||||
@ -532,4 +543,43 @@ export class Registry {
|
|||||||
assert(this.registryConfig.authority, "Authority doesn't exist");
|
assert(this.registryConfig.authority, "Authority doesn't exist");
|
||||||
return `lrn://${this.registryConfig.authority}/applications/${appName}`;
|
return `lrn://${this.registryConfig.authority}/applications/${appName}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async generateConfigHash(
|
||||||
|
environmentVariables: { [key: string]: string },
|
||||||
|
requesterAddress: string,
|
||||||
|
pubKey: string,
|
||||||
|
url: string,
|
||||||
|
): Promise<string> {
|
||||||
|
// Config to be encrypted
|
||||||
|
const config = {
|
||||||
|
authorized: [requesterAddress],
|
||||||
|
config: { env: environmentVariables },
|
||||||
|
};
|
||||||
|
|
||||||
|
// Serialize the config
|
||||||
|
const serialized = JSON.stringify(config, null, 2);
|
||||||
|
|
||||||
|
const armoredKey = `-----BEGIN PGP PUBLIC KEY BLOCK-----\n\n${pubKey}\n\n-----END PGP PUBLIC KEY BLOCK-----`;
|
||||||
|
const publicKey = await openpgp.readKey({ armoredKey });
|
||||||
|
|
||||||
|
// Encrypt the config
|
||||||
|
const encrypted = await openpgp.encrypt({
|
||||||
|
message: await openpgp.createMessage({ text: serialized }),
|
||||||
|
encryptionKeys: publicKey,
|
||||||
|
format: 'binary',
|
||||||
|
});
|
||||||
|
|
||||||
|
// Get the hash after uploading encrypted config
|
||||||
|
const response = await fetch(`${url}/upload/config`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/octet-stream',
|
||||||
|
},
|
||||||
|
body: encrypted,
|
||||||
|
});
|
||||||
|
|
||||||
|
const configHash = await response.json();
|
||||||
|
|
||||||
|
return configHash.id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -641,6 +641,7 @@ export class Service {
|
|||||||
|
|
||||||
const newDeployment = await this.createDeploymentFromData(userId, data, deployer!.deployerLrn!, applicationRecordId, applicationRecordData);
|
const newDeployment = await this.createDeploymentFromData(userId, data, deployer!.deployerLrn!, applicationRecordId, applicationRecordData);
|
||||||
|
|
||||||
|
const address = await this.getAddress();
|
||||||
const { repo, repoUrl } = await getRepoDetails(octokit, data.project.repository, data.commitHash);
|
const { repo, repoUrl } = await getRepoDetails(octokit, data.project.repository, data.commitHash);
|
||||||
const environmentVariablesObj = await this.getEnvVariables(data.project!.id!);
|
const environmentVariablesObj = await this.getEnvVariables(data.project!.id!);
|
||||||
// To set project DNS
|
// To set project DNS
|
||||||
@ -654,8 +655,11 @@ export class Service {
|
|||||||
environmentVariables: environmentVariablesObj,
|
environmentVariables: environmentVariablesObj,
|
||||||
dns: `${newDeployment.project.name}`,
|
dns: `${newDeployment.project.name}`,
|
||||||
lrn: deployer!.deployerLrn!,
|
lrn: deployer!.deployerLrn!,
|
||||||
|
apiUrl: deployer!.deployerApiUrl!,
|
||||||
payment: data.project.txHash,
|
payment: data.project.txHash,
|
||||||
auctionId: data.project.auctionId
|
auctionId: data.project.auctionId,
|
||||||
|
requesterAddress: address,
|
||||||
|
publicKey: deployer!.publicKey!
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -665,10 +669,13 @@ export class Service {
|
|||||||
appName: repo,
|
appName: repo,
|
||||||
repository: repoUrl,
|
repository: repoUrl,
|
||||||
lrn: deployer!.deployerLrn!,
|
lrn: deployer!.deployerLrn!,
|
||||||
|
apiUrl: deployer!.deployerApiUrl!,
|
||||||
environmentVariables: environmentVariablesObj,
|
environmentVariables: environmentVariablesObj,
|
||||||
dns: `${newDeployment.project.name}-${newDeployment.id}`,
|
dns: `${newDeployment.project.name}-${newDeployment.id}`,
|
||||||
payment: data.project.txHash,
|
payment: data.project.txHash,
|
||||||
auctionId: data.project.auctionId
|
auctionId: data.project.auctionId,
|
||||||
|
requesterAddress: address,
|
||||||
|
publicKey: deployer!.publicKey!
|
||||||
});
|
});
|
||||||
|
|
||||||
await this.db.updateDeploymentById(newDeployment.id, {
|
await this.db.updateDeploymentById(newDeployment.id, {
|
||||||
@ -720,6 +727,7 @@ export class Service {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const newDeployment = await this.createDeploymentFromData(project.ownerId!, deploymentData, deployerLrn, applicationRecordId, applicationRecordData);
|
const newDeployment = await this.createDeploymentFromData(project.ownerId!, deploymentData, deployerLrn, applicationRecordId, applicationRecordData);
|
||||||
|
const address = await this.getAddress();
|
||||||
|
|
||||||
const environmentVariablesObj = await this.getEnvVariables(project!.id!);
|
const environmentVariablesObj = await this.getEnvVariables(project!.id!);
|
||||||
// To set project DNS
|
// To set project DNS
|
||||||
@ -734,6 +742,9 @@ export class Service {
|
|||||||
dns: `${newDeployment.project.name}`,
|
dns: `${newDeployment.project.name}`,
|
||||||
auctionId: project.auctionId!,
|
auctionId: project.auctionId!,
|
||||||
lrn: deployerLrn,
|
lrn: deployerLrn,
|
||||||
|
apiUrl: deployer!.deployerApiUrl!,
|
||||||
|
requesterAddress: address,
|
||||||
|
publicKey: deployer!.publicKey!
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -745,8 +756,11 @@ export class Service {
|
|||||||
repository: repoUrl,
|
repository: repoUrl,
|
||||||
auctionId: project.auctionId!,
|
auctionId: project.auctionId!,
|
||||||
lrn: deployerLrn,
|
lrn: deployerLrn,
|
||||||
|
apiUrl: deployer!.deployerApiUrl!,
|
||||||
environmentVariables: environmentVariablesObj,
|
environmentVariables: environmentVariablesObj,
|
||||||
dns: `${newDeployment.project.name}-${newDeployment.id}`,
|
dns: `${newDeployment.project.name}-${newDeployment.id}`,
|
||||||
|
requesterAddress: address,
|
||||||
|
publicKey: deployer!.publicKey!
|
||||||
});
|
});
|
||||||
|
|
||||||
await this.db.updateDeploymentById(newDeployment.id, {
|
await this.db.updateDeploymentById(newDeployment.id, {
|
||||||
@ -1434,6 +1448,7 @@ export class Service {
|
|||||||
const deployerApiUrl = record.attributes.apiUrl;
|
const deployerApiUrl = record.attributes.apiUrl;
|
||||||
const minimumPayment = record.attributes.minimumPayment;
|
const minimumPayment = record.attributes.minimumPayment;
|
||||||
const paymentAddress = record.attributes.paymentAddress;
|
const paymentAddress = record.attributes.paymentAddress;
|
||||||
|
const publicKey = record.attributes.publicKey;
|
||||||
const baseDomain = deployerApiUrl.substring(deployerApiUrl.indexOf('.') + 1);
|
const baseDomain = deployerApiUrl.substring(deployerApiUrl.indexOf('.') + 1);
|
||||||
|
|
||||||
const deployerData = {
|
const deployerData = {
|
||||||
@ -1442,7 +1457,8 @@ export class Service {
|
|||||||
deployerApiUrl,
|
deployerApiUrl,
|
||||||
baseDomain,
|
baseDomain,
|
||||||
minimumPayment,
|
minimumPayment,
|
||||||
paymentAddress
|
paymentAddress,
|
||||||
|
publicKey
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: Update deployers table in a separate job
|
// TODO: Update deployers table in a separate job
|
||||||
|
@ -10,7 +10,7 @@ import { Deployment, DeploymentStatus, Environment } from '../src/entity/Deploym
|
|||||||
const log = debug('snowball:publish-deploy-records');
|
const log = debug('snowball:publish-deploy-records');
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
const { registryConfig, database, misc } = await getConfig();
|
const { registryConfig, database } = await getConfig();
|
||||||
|
|
||||||
const registry = new Registry(
|
const registry = new Registry(
|
||||||
registryConfig.gqlEndpoint,
|
registryConfig.gqlEndpoint,
|
||||||
|
@ -14407,6 +14407,11 @@ open@^8.0.4, open@^8.4.0:
|
|||||||
is-docker "^2.1.1"
|
is-docker "^2.1.1"
|
||||||
is-wsl "^2.2.0"
|
is-wsl "^2.2.0"
|
||||||
|
|
||||||
|
openpgp@^6.0.1:
|
||||||
|
version "6.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/openpgp/-/openpgp-6.0.1.tgz#ab3a2c08a3e23ac7f85c4fc62a3e715d50dc08fb"
|
||||||
|
integrity sha512-3lReDKjgWsKFArZT4Y/yj7/Q0q6/VhXarn4WqKEkyiBWckNjrThSGoB1t0IKo3Ke0ClvBpyQfTwumkGUkxOwww==
|
||||||
|
|
||||||
optimism@^0.18.0:
|
optimism@^0.18.0:
|
||||||
version "0.18.0"
|
version "0.18.0"
|
||||||
resolved "https://registry.yarnpkg.com/optimism/-/optimism-0.18.0.tgz#e7bb38b24715f3fdad8a9a7fc18e999144bbfa63"
|
resolved "https://registry.yarnpkg.com/optimism/-/optimism-0.18.0.tgz#e7bb38b24715f3fdad8a9a7fc18e999144bbfa63"
|
||||||
|
Loading…
Reference in New Issue
Block a user