Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Root encrypted data to kms encryption #2827

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

akhilmhdh
Copy link
Member

Description 📣

This PR adds migration to remove all directly root encrypted schemas with our new kms architecture. This also allows migrations to use kms features.

All the unused fields are kept nullable and not dropped. Will be doing a rolling migration for this to remove it later.

Type ✨

  • Bug fix
  • New feature
  • Improvement
  • Breaking change
  • Documentation

Tests 🛠️

# Here's some code block to paste some code snippets

@akhilmhdh akhilmhdh requested a review from maidul98 December 1, 2024 17:43
@akhilmhdh akhilmhdh self-assigned this Dec 1, 2024
Copy link

gitguardian bot commented Dec 1, 2024

️✅ There are no secrets present in this pull request anymore.

If these secrets were true positive and are still valid, we highly recommend you to revoke them.
While these secrets were previously flagged, we no longer have a reference to the
specific commits where they were detected. Once a secret has been leaked into a git
repository, you should consider it compromised, even if it was deleted immediately.
Find here more information about risks.


🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.

Copy link
Collaborator

@maidul98 maidul98 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left some small comments. For manual testing i tried with:

  • ladap config [good]
  • dynamic secret with pg [seems to save and all but says the password is wrong?]
  • secret rotation [seems to save and all but says the password is wrong?]
  • webhooks [good]

Also what about integrations and are there any other items we are missing on this pass? What about the server admin slack secrets?
CleanShot 2024-12-10 at 21 34 41@2x

DB_USER: zpStr(z.string().describe("Postgres database username").optional()),
DB_PASSWORD: zpStr(z.string().describe("Postgres database password").optional()),
DB_NAME: zpStr(z.string().describe("Postgres database name").optional()),
// TODO(akhilmhdh): will be changed to one
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Q: change what?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment from previous config. It means the Encryption key and Root encryption key will become one key

ENCRYPTION_KEY: zpStr(z.string().optional()),
ROOT_ENCRYPTION_KEY: zpStr(z.string().optional()),
// HSM
HSM_LIB_PATH: zpStr(z.string().optional()),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's say the hsm was set up for this instance but the user didn't pass in the hsm params, then what wil happen? I think we should check if this instance has hsm configured and tell them these are required

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The HSM service handles it already.

createdAt: z.date(),
updatedAt: z.date(),
groupSearchBase: z.string().default(""),
groupSearchFilter: z.string().default(""),
searchFilter: z.string().default(""),
uniqueUserAttribute: z.string().default("")
uniqueUserAttribute: z.string().default(""),
encryptedLdapBindDN: zodBuffer,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: in the other auth methods, you don't refer to the auth method in the field but for this one you do. to keep it consistent, maybe omit the ldap for these fields?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's added because the field is already used. There exist a field encryptedBindDN.

@@ -25,7 +27,9 @@ export const WebhooksSchema = z.object({
urlCipherText: z.string().nullable().optional(),
urlIV: z.string().nullable().optional(),
urlTag: z.string().nullable().optional(),
type: z.string().default("general").nullable().optional()
type: z.string().default("general").nullable().optional(),
encryptedPassKey: zodBuffer.nullable().optional(),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: encryptedWebhookKey

@@ -187,7 +188,7 @@ export const registerLdapRouter = async (server: FastifyZodProvider) => {
caCert: z.string().trim().default("")
}),
response: {
200: LdapConfigsSchema
200: SanitizedLdapConfigSchema
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I assume this is to filter out and define ony what we want the response fields to be like? Why don't we start a pattern where we call the schema of a API response V1APINameResponseSchema? This would be more clear

@@ -16,28 +15,14 @@ import { WebhookType } from "./webhook-types";

const WEBHOOK_TRIGGER_TIMEOUT = 15 * 1000;

export const decryptWebhookDetails = (webhook: TWebhooks) => {
const { keyEncoding, iv, encryptedSecretKey, tag, urlCipherText, urlIV, urlTag, url } = webhook;
export const decryptWebhookDetails = (webhook: TWebhooks, decryptor: (value: Buffer) => string) => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not make a instance of the decrypted here from kms service? i see you are passing on the decryptor function it self. could we pass on the decrypted data in here so we keep those things a little more isolated?

@@ -0,0 +1,19 @@
export const newRingBuffer = <T>(bufferSize = 10) => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: This isn't a real ring buffer and more of a key-value store. Maybe call it createCircularCache

await knex.schema.alterTable(TableName.Webhook, (t) => {
if (!hasEncryptedKey) t.binary("encryptedPassKey");
if (!hasEncryptedUrl) t.binary("encryptedUrl");
if (hasUrl) t.string("url").nullable().alter();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

did you mean does not have url? because url doesn't exist currently

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

URL does exist in webhook

updatedWebhooks.slice(i, i + BATCH_SIZE).map((el) => ({
id: el.id,
envId: el.envId,
url: "",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is url being set to empty?

type: KmsDataKey.SecretManager,
projectId
});
projectEncryptionRingBuffer.push(projectId, projectKmsService);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if the cache loops over then don't you lose the id to projectKmsService and that would mean you may be encrypting the same project with one or more kms key?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes we loose the entire thing. It would also means we cannot find it anymore with project id, so we load it to the cache again

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants