- fix(management):
K8SSecret/K8STLSSecrAdd jobs no longer reportSuccesswhen the Kubernetes write silently fails (#91).ManagementBase.HandleAddnow checks the handler's returnedV1Secretand fails the job with an actionable message when the write produced no result. - fix(client):
CreateOrUpdateCertificateStoreSecretnow uses a read-then-branch strategy (matching the JKS/PKCS12 path) instead of a blind create with a free-text"Conflict"exception-message match. Existence is checked via a typed 404; a typedHttpStatusCode.Conflicton a create race falls back to update; all otherHttpOperationExceptions propagate and fail the job instead of being swallowed into a silentnullreturn.
- refactor(jobs): Monolithic job classes replaced with store-type-specific classes. Each store type (
K8SCert,K8SCluster,K8SJKS,K8SNS,K8SPKCS12,K8SSecret,K8STLSSecr) now has dedicatedInventory,Management, andDiscoveryjob classes underJobs/StoreTypes/<StoreType>/. Themanifest.jsonhas been updated accordingly. Any external references to job class namespaces must be updated. - refactor(jobs): Dead properties removed from
JobBase:KubeHost,KubeCluster,SkipTlsValidation,OperationType,Overwrite,KeyEntry,ManagementConfig,DiscoveryConfig,InventoryConfig. Any code referencing these properties must be updated. - refactor(client): Monolithic
KubeClientsplit into focused components (KubeClient,SecretOperations,CertificateOperations,KubeconfigParser). Direct instantiation of the old client is no longer supported. - refactor(handlers): Secret operation logic extracted into a handler strategy pattern (
ISecretHandler,SecretHandlerFactory). Store-type-specific logic no longer lives in job base classes. - refactor(services): Business logic extracted from
JobBaseinto dedicated service classes (StoreConfigurationParser,PasswordResolver,CertificateChainExtractor,JobCertificateParser,StorePathResolver). - refactor(keystores):
KeystoreManagerclass removed. JKS and PKCS12 operations are now handled byJksSecretHandlerandPkcs12SecretHandlerrespectively. - chore(crypto): Remove all usage of
System.Security.Cryptography.X509Certificate2for certificate store operations. All cryptographic operations now use BouncyCastle exclusively.
- feat(compat): Add
.NET 10target — extension now ships builds for bothnet8.0andnet10.0, supporting Keyfactor Command 24.x (net8.0) and 25.x+ (net10.0). - feat(terraform): Add reusable Terraform modules for all 7 store types to support dev/test cluster provisioning.
- feat(security): Kubernetes secret replace operations now propagate
resourceVersionto prevent lost-update races under concurrent writes. - feat(validation):
StorePathResolvernow throwsArgumentExceptionon namespace or secret name components that do not conform to Kubernetes DNS subdomain rules, and throwsConfigurationExceptionfor store paths with 5+ segments, preventing silent misrouting. - feat(logging): Add
LoggingUtilitieswith safe redaction helpers for passwords, private keys, certificates, kubeconfigs, and tokens — sensitive values are never written to logs. - feat(auth): Add client certificate authentication support (Option 2) — new
generate_client_cert_creds.shscript,kubernetes_svc_account_cert_auth.yaml, andexample_kubeconfig_cert.json. No plugin code changes required; the underlying Kubernetes C# client already supportsclient-certificate-data/client-key-datakubeconfig fields. - feat(auth): Add in-cluster / pod identity authentication (Option 3) — when the Universal Orchestrator runs as a Kubernetes pod, the extension detects
KUBERNETES_SERVICE_HOSTand callsKubernetesClientConfiguration.InClusterConfig()automatically. No kubeconfig is required for that cluster; leave Server Password blank (select "No value" in Command UI). Newkeyfactor-orchestrator-deployment.yamldeployment manifest included. - feat(audit): Add structured
AUDITlog entries forstore_access(STARTED/COMPLETED/FAILED) in Inventory, Management, and Discovery base classes, andsecret_read,secret_write,secret_deleteinSecretOperations— satisfies SOX/SOC2 audit trail requirements.
- fix(inventory): Null reference when secret not found now throws
StoreNotFoundExceptioninstead of propagating as an unhandled null dereference. - fix(client):
ReadBuddyPassthrowsStoreNotFoundExceptionon missing password secret rather than returning null. - fix(chain):
SeparateChain=trueis silently overridden tofalsewhenIncludeCertChain=false— there is no chain to separate. - fix(client):
config.UseSSLwas read from the Keyfactor framework job configuration but never forwarded toKubeCertificateManagerClient. The value is now threaded through all threeInitializeStoreoverloads and passed to the client constructor. - fix(management):
HandleRemovenow returnsOrchestratorJobStatusJobResult.Warning(notSuccess) when the target secret does not exist, so Command job history correctly distinguishes "no-op" from a successful removal. - fix(handlers):
JksSecretHandler,Pkcs12SecretHandler, andCertificateSecretHandlernow catch typedHttpOperationExceptionwithHttpStatusCode.NotFoundinstead of string-matchingex.Message.Contains("NotFound"), closing a detection gap for non-English error messages. - fix(security):
LoggingUtilities.RedactKubeconfigvalidates JSON structure before applying the label; non-JSON input returns***POSSIBLY_MALFORMED_CREDENTIAL*** (length: N)instead of silently leaking content. - fix(security):
KubeconfigParser.CheckTlsVerifyOverridepromotes TLS-skip notification fromLogWarningtoLogErrorwith aSECURITY_CONFIG_OVERRIDEstructured field, ensuring the override is visible in SOC2 audit log streams. - fix(security): Remove
GetPasswordCorrelationId— SHA-256 hashing of low-entropy passwords is reversible via dictionary attack and provides no audit value. All call sites already haveRedactPasswordin place. - fix(scripts):
get_service_account_creds.shandcreate_service_account.shnow use directkubectl … -o jsonpath='{.data.token}'queries instead of fragilegrep/awkpipelines, fixing silent failures on Kubernetes v1.22+ clusters where service accounts no longer receive auto-created token Secrets.
- chore(tests): Add
CachedCertificateProviderfor thread-safe certificate reuse across tests, reducing test suite runtime significantly. - chore(docs): Add
docs/ARCHITECTURE.mddocumenting layer architecture, data flow, design patterns, and authentication model. - chore(docs): Update compatibility section to include Command 24.x and 25.x and net8.0/net10.0 build matrix.
- chore(docs): Rewrite
scripts/kubernetes/README.mdto document all three authentication options (SA token, client certificate, in-cluster) with a comparison table, setup scripts, example kubeconfigs, and Command UI instructions. - chore(security): Credential fields (
ServerPassword,KubeSvcCreds) are zeroed out inJobBaseimmediately after the Kubernetes client is constructed — credentials are not held in memory longer than necessary. - chore(security): PAM credential resolution outcome promoted from
LogTracetoLogInformationwith SUCCESS/EMPTY_OR_FAILED outcome tags for SOC2 visibility.
- feat(storetypes):
K8SCertsupports inventory of all signed K8S cluster CSRs. - feat(crypto): Replace
X509Certificate2with BouncyCastle for all cryptographic operations, improving cross-platform compatibility. - feat(crypto): Add
CertificateUtilitiesclass with comprehensive certificate parsing, key extraction, and format detection. - feat(crypto): Support for all key types:
RSA (1024-8192 bit), ECDSA (P-256, P-384, P-521), DSA (1024, 2048 bit), Ed25519, Ed448.
- fix(client): Fix null reference issues in kubeconfig parsing when optional fields are missing.
- fix(inventory): Initialize logger before all other operations to ensure proper error reporting.
- fix(management): Fix alias parsing for
K8SNSandK8SClusterstore-types when alias contains multiple path segments. - fix(management): Add
IncludeCertChainat base job level, and include in management jobs. - fix(management):
K8SPKCS12andK8SJKSrespectIncludeCertChainflag. - fix(management): "Create if missing" jobs (
CertStoreOperationType.Create) no longer fail with "Unknown operation type: Create".Createis now routed identically toAdd. - fix(management):
K8SJKSandK8SPKCS12CreateEmptyStorenow uses the buddy-secret password when one is configured, instead of always using an empty password. - fix(management):
K8SJKSandK8SPKCS12alias routing now correctly interprets the<fieldName>/<certAlias>format. Previously,HandleAddandHandleRemovealways wrote to the first existing field in the secret and passed the full alias string (e.g.mystore.jks/default) to the keystore serializer; now the field name selects the target K8S secret field and only the short cert alias is used inside the JKS/PKCS12 file.
- chore(tests): Add comprehensive unit test suite covering all store types and cryptographic operations.
- chore(tests): Add integration test suite validating end-to-end operations against live Kubernetes clusters.
- chore(tests): Add alias routing regression tests (
AliasRoutingRegressionTests) with 8 unit tests covering JKS and PKCS12 field-selection and certAlias correctness. - chore(tests): Add 4 integration tests each to
K8SJKSStoreIntegrationTestsandK8SPKCS12StoreIntegrationTestsvalidating end-to-end<fieldName>/<certAlias>alias routing (field written to, cert alias inside keystore, inventory alias format, and remove from named field). - chore(tests): Add unit tests for all three constructors of
JkSisPkcs12Exception,InvalidK8SSecretException, andStoreNotFoundException(previously at 0% line coverage). - chore(tests): Add 10 unit tests for
CertificateChainExtractorcovering null/empty inputs, DER fallback, invalid data, andca.crtchain handling (coverage: 75% → 98.9%). - chore(tests): Add 26 no-network unit tests for
CertificateSecretHandler,ClusterSecretHandler, andNamespaceSecretHandlercovering property assertions,NotSupportedExceptionthrows, and alias-parsingArgumentExceptionpaths (coverage: ~69–78% → ~82–89%). - chore(ci): Add GitHub Actions workflows for unit tests, integration tests, code quality, and security scanning.
- chore(ci): Add CodeQL, dependency review, SBOM generation, and license compliance workflows.
- chore(ci): Add PR quality gate with semantic versioning validation and auto-labeling.
- chore(docs): Document supported key types for all store types.
- chore(util): Add verbose logging to PAM credential resolver.
- chore(refactor): Remove dead code from
JobBase— unused static arrays, dead properties, unusedWarningJob(),HasPrivateKey(), andCertChainSeparator. - chore(refactor): Remove unreachable branches from
KubeClient.GetKubeClient()— theelse if (k8SConfiguration == null)and file-path fallback branches were provably dead becauseKubeconfigParser.Parse()always throws on failure rather than returning null. Cyclomatic complexity reduced from 14 to 6, CRAP score from 137 to 26.8. - chore(refactor): Simplify JKS serializer
CreateOrUpdateJks— extractLoadExistingJksStore(),LoadNewCertificate(),SaveJksStore(),PasswordToChars()helpers. CRAP score reduced from 60 to 16. - chore(refactor): Simplify PKCS12 serializer
CreateOrUpdatePkcs12— same helper extraction pattern. CRAP score reduced from 36 to 16. - chore(refactor): Simplify
GetStorePath()inJobBase— extractDeriveSecretType()andNormalizeSecretTypeForPath()helpers, make method private.
- fix(storetypes):
K8SJKSandK8SPKCS12storetypes using a separatek8ssecret for store password does not crash on missing or invalid secret field name. - fix(storetypes):
K8SJKSwhere JKS files created using Keytool v20+ will be recognized as JKS files. - fix(storetypes):
K8SJKSandK8SPKCS12store/buddy passwords ending with a\ncharacter will be trimmed to not include the newline. - fix(storetypes): All store-types now support
IncludeCertChainparameter. This defaults totrue. - fix(storetypes):
K8STLSSECRandK8SSecretsupportSeparateChainproperty. This defaults tofalse.
- chore(docs): Update documentation format
- chore(deps): Bump
BouncyCastle.Cryptographytov2.6.2.
- fix(management):
K8SNSmanagement jobs handlestorepathparsed length is less than expected.
- feat(client): Retry interrupted connections to k8s cluster.
- fix(client): Provide useful error message when credentials are empty and/or invalid format.
- fix(base): Prevent uninitialized client reference in
JobBase.
- chore(deps): Bump
Keyfactor.Loggingtov1.1.2. - chore(deps): Bump
Keyfactor.PKItov5.5.0.
- fix(management): Management jobs for
K8STLSSecretandK8SSecrettypes handle ECC keys. - fix(manifest): Update store-type definitions to include params
IncludeCertChainandSeparateChain - fix(docs): Update screenshots for
K8SClusterandK8SNSstore types custom fields. - fix(client): Handle skip TLS flag when passed to a job.
- feat(storetypes):
K8SPKCS12store type added to support PKCS12, .P12, PFX, files in K8Sopaquesecrets. - feat(storetypes):
K8SJKSstore type added to support JKS files in K8Sopaquesecrets. - feat(storetypes):
K8SCLUSTERstore type added to support PEM files in K8Sopaqueandtlssecrets for an entire cluster as a single store. - feat(storetypes):
K8SNSstore type added to support PEM files in K8Sopaqueandtlssecrets for a single namespace as a single store. - feat(discovery): Support added for:
K8SNS,K8SPKCS12,K8SJKSstore types. - feat(management): Support added for:,
K8SCLUSTER,K8SNS,K8SPKCS12,K8SJKSstore types. - feat(inventory): Support added for:
K8SCLUSTER,K8SNS,K8SPKCS12,K8SJKSstore types.
- fix(base): If unable to convert to x509Certificate2 object then just use raw bytes from job.
- fix(client): Replace remaining "private_keys" refs to "tls.key"
- fix(management): Private keys coming from Keyfactor command are not stored unencrypted in secrets.
- fix(management): Remove check for cert bytes in HandleTlsSecret
- fix(management): Condition for handling "create_store" includes check of PEM and alias.
- chore(scripts): Add script to stand up Hashicorp Vault CA and create some certs then push them into K8S secrets.
- fix(management): Opaque secrets now manage tls.crt and tls.key rather than
certificatesandprivate_keys. Only a single cert and key are supported.
- fix(base): Add additional logic extracting private keys
- fix(base): Verbose logging.
- fix(client): Discovery locations now include cluster name.
- fix(discovery): StorePath now includes cluster name from kubeconfig credentials.
- fix(management): When creating
X509Certificate2include flag to allow export. - fix(scripts): Fixed k8s service account scripts to default to index 0 and added notes about assumption.
- chore(docs): Added docs about
StorePath
- fix(base): Add support for empty or null
ServerUsernameand default tokubeconfig - fix(base): Throw configuration exception if
ServerPasswordis null or empty. - fix(client): Init kf logger properly.
- fix(client): Remove will search all secret keys to check for cert rather than just managed keys.
- fix(discovery): Remove duplicate locations from results and print out discovered locations in the message.
- fix(discovery): Lists all namespaces and then checks if namespace is in the "Directories to search" parameter rather than filter by API call.
- fix(discovery): Now checks the storetype passed to determine what K8S secret type to import when checking secret keys.
- fix(inventory): Added more logging
- fix(inventory): When secret is not found on K8S inventory is assumed empty.
- fix(management): Add support for
createStore - fix(management): Enable use of "create store" tick box, which triggers an empty management job.
- fix(manifest): Capability names match docs
- fix(store-types): Update store types to require server and remove
KubeSvcCredsfield.
- chore(docs): Removed KubeSvcCreds reference from PAM stub.
- fix(base): Parse
KubeNamespaceandKubeSecretNamefrom storepath if contains/ - fix(inventory): Allowing for secret key tls.crt and tls.key for
Opaquesecret types. - fix(inventory): Returned certs list now returns list of certs.
- chore(docs): Remove references to
KubeSvcCredsfield, and instead forceNeeds Serverwhich implicitly adds fields forServerUsernameandServerPassword
- Initial release