feat(M47): add Kubernetes Secrets target + AWS ACM PCA issuer connectors

Implement both M47 connectors with full cross-layer wiring:

Kubernetes Secrets target: DNS-1123 validation, kubernetes.io/tls Secret
create-or-update, chain concatenation, serial number validation, Helm
RBAC gating. 18 tests.

AWS ACM Private CA issuer: synchronous issuance (like Vault), ARN regex
validation, RFC 5280 revocation reason mapping, CA cert retrieval,
factory + env var seeding. 23 tests.

Cross-cutting: domain types, service validation, config, factory, agent
dispatch, frontend (TargetsPage, issuerTypes), OpenAPI, seed data, Helm
chart, connectors docs, README. Testing docs (testing-guide, qa-test-guide,
qa_test.go) with Parts thematically integrated near related connectors.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Shankar
2026-04-07 20:21:09 -04:00
parent f17027c62b
commit e72f06f35b
22 changed files with 2620 additions and 18 deletions
+13
View File
@@ -154,6 +154,19 @@ export const issuerTypes: IssuerTypeConfig[] = [
{ key: 'ttl', label: 'Default TTL', required: false, placeholder: '8760h' },
],
},
{
id: 'AWSACMPCA',
name: 'AWS ACM Private CA',
description: 'AWS Certificate Manager Private Certificate Authority \u2014 managed private CA on AWS',
icon: '\u2601\uFE0F',
configFields: [
{ key: 'region', label: 'AWS Region', required: true, placeholder: 'us-east-1' },
{ key: 'ca_arn', label: 'CA ARN', required: true, placeholder: 'arn:aws:acm-pca:us-east-1:123456789012:certificate-authority/...' },
{ key: 'signing_algorithm', label: 'Signing Algorithm', required: false, type: 'select', options: ['SHA256WITHRSA', 'SHA384WITHRSA', 'SHA512WITHRSA', 'SHA256WITHECDSA', 'SHA384WITHECDSA', 'SHA512WITHECDSA'], defaultValue: 'SHA256WITHRSA' },
{ key: 'validity_days', label: 'Validity (days)', required: false, type: 'number', placeholder: '365' },
{ key: 'template_arn', label: 'Template ARN (optional)', required: false, placeholder: 'arn:aws:acm-pca:...:template/...' },
],
},
{
id: 'entrust',
name: 'Entrust',
+1
View File
@@ -24,6 +24,7 @@ const typeLabels: Record<string, string> = {
SSH: 'SSH',
WinCertStore: 'Windows Cert Store',
JavaKeystore: 'Java Keystore',
KubernetesSecrets: 'Kubernetes Secrets',
};
function InfoRow({ label, value }: { label: string; value: React.ReactNode }) {
+8
View File
@@ -24,6 +24,7 @@ const typeLabels: Record<string, string> = {
SSH: 'SSH',
WinCertStore: 'Windows Cert Store',
JavaKeystore: 'Java Keystore',
KubernetesSecrets: 'Kubernetes Secrets',
};
const TARGET_TYPES = [
@@ -40,6 +41,7 @@ const TARGET_TYPES = [
{ value: 'SSH', label: 'SSH', description: 'Agentless deployment via SSH/SFTP — deploy to any Linux/Unix server without installing an agent' },
{ value: 'WinCertStore', label: 'Windows Cert Store', description: 'Import certificates into Windows Certificate Store for Exchange, RDP, SQL Server, ADFS' },
{ value: 'JavaKeystore', label: 'Java Keystore', description: 'Deploy to JKS/PKCS#12 keystores for Tomcat, Jetty, Kafka, Elasticsearch, and JVM services' },
{ value: 'KubernetesSecrets', label: 'Kubernetes Secrets', description: 'Deploy as kubernetes.io/tls Secrets for Ingress controllers, service meshes, and workloads' },
];
const CONFIG_FIELDS: Record<string, { key: string; label: string; placeholder: string; required?: boolean }[]> = {
@@ -162,6 +164,12 @@ const CONFIG_FIELDS: Record<string, { key: string; label: string; placeholder: s
{ key: 'reload_command', label: 'Reload Command (optional)', placeholder: 'systemctl restart tomcat' },
{ key: 'keytool_path', label: 'Keytool Path (optional)', placeholder: 'keytool (default, from PATH)' },
],
KubernetesSecrets: [
{ key: 'namespace', label: 'Namespace', placeholder: 'default', required: true },
{ key: 'secret_name', label: 'Secret Name', placeholder: 'my-tls-secret', required: true },
{ key: 'labels', label: 'Labels (JSON)', placeholder: '{"app": "my-app"}' },
{ key: 'kubeconfig_path', label: 'Kubeconfig Path (optional)', placeholder: '/home/agent/.kube/config' },
],
};
function CreateTargetWizard({ onClose, onSuccess }: { onClose: () => void; onSuccess: () => void }) {