Skip to content

feat: platform secrets as sealed secrets#932

Open
ferruhcihan wants to merge 22 commits intomainfrom
APL-523
Open

feat: platform secrets as sealed secrets#932
ferruhcihan wants to merge 22 commits intomainfrom
APL-523

Conversation

@ferruhcihan
Copy link
Collaborator

@ferruhcihan ferruhcihan commented Feb 24, 2026

📌 Summary

PRs: apl-core | apl-tasks

@ferruhcihan ferruhcihan marked this pull request as ready for review March 9, 2026 10:17
Copy link
Contributor

@CasLubbers CasLubbers left a comment

Choose a reason for hiding this comment

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

Also really good improvmenets in here. I didn't saw any changes for the settings. Is that correct? I don't know from the top of my mind if we can change any secret values in the settings.

}

export async function encryptSecretValue(pem: string, namespace: string, value: string): Promise<string> {
const { encryptSecretItem } = await import('@linode/kubeseal-encrypt')
Copy link
Contributor

Choose a reason for hiding this comment

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

Does this import need to be in the function?

this.sessionId = sessionId ?? 'main'
}

private static sealedSecretToUserData(manifest: SealedSecretManifestResponse): UserSecretData {
Copy link
Contributor

Choose a reason for hiding this comment

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

Static functions should mostly be avoided. In this case its better to move this function outside of this class even this file because otomi-stack is already quite big

} as UserSecretData
}

private async listUserSecretData(): Promise<UserSecretData[]> {
Copy link
Contributor

Choose a reason for hiding this comment

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

In the future we could also opt for reading the users directly from the k8s cluster. Then we can remove this code outside of the otomi-stack

const { metadata } = data

// Server-side encryption fallback: if any encryptedData values are plain text, encrypt them
if (data.spec.encryptedData && Object.keys(data.spec.encryptedData).length > 0) {
Copy link
Contributor

Choose a reason for hiding this comment

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

How does this check if the values are in plain text? Now it checks the length is that correct?

const username = (otomi?.git?.username ?? '') as string
const password = (otomi?.git?.password ?? '') as string
const { cluster } = this.getSettings(['cluster'])
const username = env.GIT_USER
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think I saw that we pass down the git user through the enviroment variables. We should adjust apl-core

Copy link
Contributor

@CasLubbers CasLubbers left a comment

Choose a reason for hiding this comment

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

Only some nice to have changes to make the code more readable. Rest looks good to me

for (const [, content] of files) {
settings[name] = content?.spec || content
// Merge sealed secret encrypted data back into settings at their original dot-paths
const valuesSchema = await getValuesSchema()
Copy link
Contributor

Choose a reason for hiding this comment

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

Would be good to put this fetch of the sealed secrets in a function with a clear name of what it does

}

settings[settingId] = removeBlankAttributes(updatedSettingsData[settingId] as Record<string, any>)
// Extract secrets from settings data and store as SealedSecret
Copy link
Contributor

Choose a reason for hiding this comment

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

This is al really complex code. It would be good to put it in to small functions with clear domain naming. So we can understand better what separate pieces are doing.

// Server-side encryption fallback: ensureEncryptedData checks each value using isEncryptedValue(),
// which detects plain text by verifying that kubeseal ciphertext is always a long (200+ chars) base64 string.
// Any value that is shorter or not valid base64 is treated as plain text and encrypted server-side.
if (data.spec.encryptedData && Object.keys(data.spec.encryptedData).length > 0) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think creating a const for this magic number would make it more understandable for me

const username = keycloak?.values?.adminUsername as string
const password = otomi?.adminPassword as string
existingUsersEmail = await getKeycloakUsers(keycloakBaseUrl, realm, username, password)
const platformSecrets = await getSecretValues('otomi-platform-secrets', 'apl-secrets')
Copy link
Contributor

Choose a reason for hiding this comment

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

Magic strings. Good to make constants

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.

3 participants