@using EntKube.Web.Data @using EntKube.Web.Services @inject VaultService VaultService @inject TenantService TenantService @using EntKube.Web.Components.Pages.Shared @* ═══════════════════════════════════════════════════════════════════ App Secrets — customer portal view for managing vault secrets scoped to a single app. Access rules: Viewer+ — list secret names, reveal values on demand Admin — add / update / delete secrets, configure K8s sync ═══════════════════════════════════════════════════════════════════ *@
Secrets — @App.Name
Application secrets stored with AES-256-GCM envelope encryption. Values are never transmitted in plain text.
@if (!vaultInitialized) {
No vault has been set up for this tenant. Ask your platform administrator to initialize it.
} else { @* ── Add Secret form (Admin only) ── *@ @if (AccessRole >= CustomerAccessRole.Admin) {
Add / Update Secret
If a secret with this name already exists it will be updated in place.
@if (errorMessage is not null) {
@errorMessage
} @if (successMessage is not null) {
@successMessage
}
} @* ── Secrets list ── *@
Stored Secrets @if (secrets is not null) { @secrets.Count }
@if (AccessRole >= CustomerAccessRole.Admin && secrets?.Any(s => s.SyncToKubernetes) == true) { }
@if (secrets is not null && secrets.Count == 0) { } else if (secrets is not null) {
@foreach (VaultSecret secret in secrets) { @* ── Reveal value row ── *@ @if (revealedSecretId == secret.Id) { } @* ── Edit value row ── *@ @if (editSecretId == secret.Id) { } @* ── K8s sync config row ── *@ @if (syncConfigSecretId == secret.Id) { } }
Name K8s Sync K8s Secret Namespace Updated Actions
@secret.Name @if (secret.SyncToKubernetes) { Enabled } else { Off } @(secret.KubernetesSecretName ?? "—") @(secret.KubernetesNamespace ?? "—") @secret.UpdatedAt.ToString("MMM d, HH:mm") @* Reveal — available to all roles *@ @* Admin-only: edit, K8s sync, delete *@ @if (AccessRole >= CustomerAccessRole.Admin) { }
Value: @if (revealLoading) {
} else { @revealedValue }
@if (clusters is not null) {
}
}
@if (syncOutput is not null) {
@syncOutput
}
@* ── Docker Registry Credentials ── *@
Docker Registry Credentials
Pull secrets for private container registries
} @code { [Parameter] public required Data.App App { get; set; } [Parameter] public Guid TenantId { get; set; } [Parameter] public CustomerAccessRole AccessRole { get; set; } private bool vaultInitialized; private List? secrets; private List? clusters; // Add form private string newSecretName = ""; private string newSecretValue = ""; private bool saving; private string? errorMessage; private string? successMessage; // Reveal private Guid? revealedSecretId; private string? revealedValue; private bool revealLoading; // Edit private Guid? editSecretId; private string editSecretValue = ""; // K8s sync config private Guid? syncConfigSecretId; private string syncSecretName = ""; private string syncNamespace = ""; private Guid syncClusterId; // Sync-to-K8s state private bool syncingSecrets; private string? syncOutput; protected override async Task OnInitializedAsync() { SecretVault? vault = await VaultService.GetVaultAsync(TenantId); vaultInitialized = vault is not null; if (vaultInitialized) { await LoadSecrets(); } // Load clusters for the K8s sync config dropdown. clusters = await TenantService.GetClustersAsync(TenantId); } private async Task LoadSecrets() { secrets = await VaultService.GetAppSecretsAsync(TenantId, App.Id); } // ──────── Add ──────── private async Task AddSecret() { errorMessage = null; successMessage = null; saving = true; try { await VaultService.SetAppSecretAsync(TenantId, App.Id, newSecretName.Trim(), newSecretValue.Trim()); successMessage = $"Secret '{newSecretName.Trim()}' saved."; newSecretName = ""; newSecretValue = ""; await LoadSecrets(); } catch (Exception ex) { errorMessage = ex.Message; } finally { saving = false; } } // ──────── Reveal ──────── private async Task RevealSecret(VaultSecret secret) { if (revealedSecretId == secret.Id) { revealedSecretId = null; revealedValue = null; return; } revealLoading = true; revealedSecretId = secret.Id; revealedValue = null; revealedValue = await VaultService.GetSecretValueByIdAsync(secret.Id); revealLoading = false; } // ──────── Edit ──────── private void StartEdit(VaultSecret secret) { editSecretId = secret.Id; editSecretValue = ""; revealedSecretId = null; revealedValue = null; } private void CancelEdit() { editSecretId = null; editSecretValue = ""; } private async Task SaveEdit() { if (editSecretId is null || string.IsNullOrWhiteSpace(editSecretValue)) return; saving = true; errorMessage = null; try { bool updated = await VaultService.UpdateSecretValueAsync(editSecretId.Value, editSecretValue.Trim()); successMessage = updated ? "Secret value updated." : null; errorMessage = updated ? null : "Failed to update secret."; } finally { saving = false; } editSecretId = null; editSecretValue = ""; await LoadSecrets(); } // ──────── Delete ──────── private async Task DeleteSecret(Guid secretId) { errorMessage = null; (bool canDelete, string? reason) = await VaultService.CanDeleteSecretAsync(secretId); if (!canDelete) { errorMessage = reason; return; } await VaultService.DeleteSecretAsync(secretId); revealedSecretId = null; editSecretId = null; await LoadSecrets(); } // ──────── K8s Sync ──────── private void ToggleSync(VaultSecret secret) { if (secret.SyncToKubernetes) { _ = DisableSync(secret.Id); } else { syncConfigSecretId = secret.Id; syncSecretName = secret.KubernetesSecretName ?? ""; syncNamespace = secret.KubernetesNamespace ?? ""; syncClusterId = secret.KubernetesClusterId ?? Guid.Empty; } } private async Task DisableSync(Guid secretId) { await VaultService.ConfigureKubernetesSyncAsync(secretId, syncEnabled: false, secretName: null, ns: null); await LoadSecrets(); } private async Task SaveSync() { if (syncConfigSecretId is null) return; Guid? clusterId = syncClusterId != Guid.Empty ? syncClusterId : (Guid?)null; await VaultService.ConfigureKubernetesSyncAsync( syncConfigSecretId.Value, syncEnabled: true, secretName: syncSecretName.Trim(), ns: syncNamespace.Trim(), clusterId: clusterId); syncConfigSecretId = null; await LoadSecrets(); } private async Task SyncAllToKubernetes() { syncingSecrets = true; syncOutput = null; try { HelmExecutionResult result = await VaultService.SyncAppSecretsToKubernetesAsync(TenantId, App.Id); syncOutput = result.Output; } finally { syncingSecrets = false; } } }