Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
294a225
refactor: extract service layer from monolithic JobBase
spbsoluble Apr 15, 2026
cfc4233
refactor: introduce handler strategy pattern for secret operations
spbsoluble Apr 15, 2026
ab3fe8a
refactor: split monolithic KubeClient into focused client components
spbsoluble Apr 15, 2026
1ee4a83
refactor: restructure job classes by store type, remove X509Certificate2
spbsoluble Apr 15, 2026
6c8f244
feat: add CachedCertificateProvider and comprehensive test suite
spbsoluble Apr 15, 2026
19bb081
docs: update CHANGELOG, ARCHITECTURE.md, Development.md, README for v…
spbsoluble Apr 15, 2026
8a46ded
docs(architecture): remove incorrect reenrollment references
spbsoluble Apr 15, 2026
c6c08a4
docs: auto-generate README and documentation [skip ci]
github-actions[bot] Apr 15, 2026
eb975df
docs: update compatibility to include Command 24.x and 25.x
spbsoluble Apr 16, 2026
454c43b
docs: auto-generate README and documentation [skip ci]
github-actions[bot] Apr 16, 2026
f574d0b
docs: call out .NET 8 and .NET 10 compatibility in README
spbsoluble Apr 16, 2026
323eab2
docs: auto-generate README and documentation [skip ci]
github-actions[bot] Apr 16, 2026
6c6f240
docs(changelog): add v2.0.0 entry
spbsoluble Apr 16, 2026
f22c2d4
docs(changelog): merge pre-rebase content into v2.0.0 and 1.3.0 entries
spbsoluble Apr 16, 2026
61a5e3b
fix: add missing Serializers directory to fix build
spbsoluble Apr 16, 2026
9371b06
docs(auth): add client certificate auth as alternative to SA token
spbsoluble Apr 21, 2026
f1568c9
docs: auto-generate README and documentation [skip ci]
github-actions[bot] Apr 21, 2026
543a10c
feat(auth): add in-cluster pod identity as third authentication option
spbsoluble Apr 21, 2026
31be2e7
docs: auto-generate README and documentation [skip ci]
github-actions[bot] Apr 21, 2026
855a8b1
docs(auth): clarify in-cluster requires "No value" for Server Passwor…
spbsoluble Apr 21, 2026
d083812
docs: auto-generate README and documentation [skip ci]
github-actions[bot] Apr 21, 2026
b163ca8
fix(security): SOX/SOC2 compliance remediations and UseSSL bug fix
spbsoluble Apr 21, 2026
7a4ec42
security: remove GetPasswordCorrelationId and update changelog
spbsoluble Apr 21, 2026
43029af
docs: remove duplicate content sections from generated README
spbsoluble Apr 23, 2026
c56b5ab
docs: auto-generate README and documentation [skip ci]
github-actions[bot] Apr 23, 2026
ca4b93d
chore(ci): revert to old doctool
spbsoluble Apr 23, 2026
6387d40
fix(k8scert): ignore storepath for csr mode and add regression coverage
spbsoluble Apr 30, 2026
d1be4b2
fix(inventory): sanitize URL cluster names in discovery location stri…
spbsoluble Jun 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 15 additions & 13 deletions .github/workflows/keyfactor-starter-workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,27 @@ name: Keyfactor Bootstrap Workflow
on:
workflow_dispatch:
pull_request:
types: [opened, closed, synchronize, edited, reopened]
types: [opened, closed, synchronize, edited, reopened, labeled]
push:
branches: [main]
create:
branches:
- 'release-*.*'
- 'release-*'


jobs:
call-starter-workflow:
uses: keyfactor/actions/.github/workflows/starter.yml@v4
with:
command_token_url: ${{ vars.COMMAND_TOKEN_URL }}
command_hostname: ${{ vars.COMMAND_HOSTNAME }}
command_base_api_path: ${{ vars.COMMAND_API_PATH }}
command_token_url: ${{ vars.COMMAND_TOKEN_URL }} # Only required for doctool generated screenshots
command_hostname: ${{ vars.COMMAND_HOSTNAME }} # Only required for doctool generated screenshots
command_base_api_path: ${{ vars.COMMAND_API_PATH }} # Only required for doctool generated screenshots
secrets:
token: ${{ secrets.V2BUILDTOKEN}}
gpg_key: ${{ secrets.KF_GPG_PRIVATE_KEY }}
gpg_pass: ${{ secrets.KF_GPG_PASSPHRASE }}
scan_token: ${{ secrets.SAST_TOKEN }}
entra_username: ${{ secrets.DOCTOOL_ENTRA_USERNAME }}
entra_password: ${{ secrets.DOCTOOL_ENTRA_PASSWD }}
command_client_id: ${{ secrets.COMMAND_CLIENT_ID }}
command_client_secret: ${{ secrets.COMMAND_CLIENT_SECRET }}
token: ${{ secrets.V2BUILDTOKEN}} # REQUIRED
gpg_key: ${{ secrets.KF_GPG_PRIVATE_KEY }} # Only required for golang builds
gpg_pass: ${{ secrets.KF_GPG_PASSPHRASE }} # Only required for golang builds
scan_token: ${{ secrets.SAST_TOKEN }} # REQUIRED
entra_username: ${{ secrets.DOCTOOL_ENTRA_USERNAME }} # Only required for doctool generated screenshots
entra_password: ${{ secrets.DOCTOOL_ENTRA_PASSWD }} # Only required for doctool generated screenshots
command_client_id: ${{ secrets.COMMAND_CLIENT_ID }} # Only required for doctool generated screenshots
command_client_secret: ${{ secrets.COMMAND_CLIENT_SECRET }} # Only required for doctool generated screenshots
15 changes: 15 additions & 0 deletions .github/workflows/test-doctool.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#name: Test doctool (dotnet)
#
#on:
# workflow_dispatch:
# push:
# branches:
# - break/major_refactor
#
#jobs:
# call-generate-readme-workflow:
# permissions:
# contents: write
# uses: Keyfactor/actions/.github/workflows/generate-readme.yml@feature/dotnet-doctool
# secrets:
# token: ${{ secrets.V2BUILDTOKEN }}
54 changes: 54 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,44 @@
# 2.0.0

## Breaking Changes
- refactor(jobs): Monolithic job classes replaced with store-type-specific classes. Each store type (`K8SCert`, `K8SCluster`, `K8SJKS`, `K8SNS`, `K8SPKCS12`, `K8SSecret`, `K8STLSSecr`) now has dedicated `Inventory`, `Management`, and `Discovery` job classes under `Jobs/StoreTypes/<StoreType>/`. The `manifest.json` has 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 `KubeClient` split 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 `JobBase` into dedicated service classes (`StoreConfigurationParser`, `PasswordResolver`, `CertificateChainExtractor`, `JobCertificateParser`, `StorePathResolver`).
- refactor(keystores): `KeystoreManager` class removed. JKS and PKCS12 operations are now handled by `JksSecretHandler` and `Pkcs12SecretHandler` respectively.
- chore(crypto): Remove all usage of `System.Security.Cryptography.X509Certificate2` for certificate store operations. All cryptographic operations now use BouncyCastle exclusively.

## Features
- feat(compat): Add `.NET 10` target — extension now ships builds for both `net8.0` and `net10.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 `resourceVersion` to prevent lost-update races under concurrent writes.
- feat(validation): `StorePathResolver` now throws `ArgumentException` on namespace or secret name components that do not conform to Kubernetes DNS subdomain rules, and throws `ConfigurationException` for store paths with 5+ segments, preventing silent misrouting.
- feat(logging): Add `LoggingUtilities` with 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.sh` script, `kubernetes_svc_account_cert_auth.yaml`, and `example_kubeconfig_cert.json`. No plugin code changes required; the underlying Kubernetes C# client already supports `client-certificate-data`/`client-key-data` kubeconfig 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_HOST` and calls `KubernetesClientConfiguration.InClusterConfig()` automatically. No kubeconfig is required for that cluster; leave Server Password blank (select "No value" in Command UI). New `keyfactor-orchestrator-deployment.yaml` deployment manifest included.
- feat(audit): Add structured `AUDIT` log entries for `store_access` (STARTED/COMPLETED/FAILED) in Inventory, Management, and Discovery base classes, and `secret_read`, `secret_write`, `secret_delete` in `SecretOperations` — satisfies SOX/SOC2 audit trail requirements.

## Bug Fixes
- fix(inventory): Null reference when secret not found now throws `StoreNotFoundException` instead of propagating as an unhandled null dereference.
- fix(client): `ReadBuddyPass` throws `StoreNotFoundException` on missing password secret rather than returning null.
- fix(chain): `SeparateChain=true` is silently overridden to `false` when `IncludeCertChain=false` — there is no chain to separate.
- fix(client): `config.UseSSL` was read from the Keyfactor framework job configuration but never forwarded to `KubeCertificateManagerClient`. The value is now threaded through all three `InitializeStore` overloads and passed to the client constructor.
- fix(management): `HandleRemove` now returns `OrchestratorJobStatusJobResult.Warning` (not `Success`) when the target secret does not exist, so Command job history correctly distinguishes "no-op" from a successful removal.
- fix(handlers): `JksSecretHandler`, `Pkcs12SecretHandler`, and `CertificateSecretHandler` now catch typed `HttpOperationException` with `HttpStatusCode.NotFound` instead of string-matching `ex.Message.Contains("NotFound")`, closing a detection gap for non-English error messages.
- fix(security): `LoggingUtilities.RedactKubeconfig` validates JSON structure before applying the label; non-JSON input returns `***POSSIBLY_MALFORMED_CREDENTIAL*** (length: N)` instead of silently leaking content.
- fix(security): `KubeconfigParser.CheckTlsVerifyOverride` promotes TLS-skip notification from `LogWarning` to `LogError` with a `SECURITY_CONFIG_OVERRIDE` structured 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 have `RedactPassword` in place.
- fix(scripts): `get_service_account_creds.sh` and `create_service_account.sh` now use direct `kubectl … -o jsonpath='{.data.token}'` queries instead of fragile `grep`/`awk` pipelines, fixing silent failures on Kubernetes v1.22+ clusters where service accounts no longer receive auto-created token Secrets.

## Chores
- chore(tests): Add `CachedCertificateProvider` for thread-safe certificate reuse across tests, reducing test suite runtime significantly.
- chore(docs): Add `docs/ARCHITECTURE.md` documenting 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.md` to 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 in `JobBase` immediately after the Kubernetes client is constructed — credentials are not held in memory longer than necessary.
- chore(security): PAM credential resolution outcome promoted from `LogTrace` to `LogInformation` with SUCCESS/EMPTY_OR_FAILED outcome tags for SOC2 visibility.

# 1.3.0

## Features
Expand All @@ -12,15 +53,28 @@
- fix(management): Fix alias parsing for `K8SNS` and `K8SCluster` store-types when alias contains multiple path segments.
- fix(management): Add `IncludeCertChain` at base job level, and include in management jobs.
- fix(management): `K8SPKCS12` and `K8SJKS` respect `IncludeCertChain` flag.
- fix(management): "Create if missing" jobs (`CertStoreOperationType.Create`) no longer fail with "Unknown operation type: Create". `Create` is now routed identically to `Add`.
- fix(management): `K8SJKS` and `K8SPKCS12` `CreateEmptyStore` now uses the buddy-secret password when one is configured, instead of always using an empty password.
- fix(management): `K8SJKS` and `K8SPKCS12` alias routing now correctly interprets the `<fieldName>/<certAlias>` format. Previously, `HandleAdd` and `HandleRemove` always 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.

## Chores:
- 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 `K8SJKSStoreIntegrationTests` and `K8SPKCS12StoreIntegrationTests` validating 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`, and `StoreNotFoundException` (previously at 0% line coverage).
- chore(tests): Add 10 unit tests for `CertificateChainExtractor` covering null/empty inputs, DER fallback, invalid data, and `ca.crt` chain handling (coverage: 75% → 98.9%).
- chore(tests): Add 26 no-network unit tests for `CertificateSecretHandler`, `ClusterSecretHandler`, and `NamespaceSecretHandler` covering property assertions, `NotSupportedException` throws, and alias-parsing `ArgumentException` paths (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, unused `WarningJob()`, `HasPrivateKey()`, and `CertChainSeparator`.
- chore(refactor): Remove unreachable branches from `KubeClient.GetKubeClient()` — the `else if (k8SConfiguration == null)` and file-path fallback branches were provably dead because `KubeconfigParser.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` — extract `LoadExistingJksStore()`, `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()` in `JobBase` — extract `DeriveSecretType()` and `NormalizeSecretTypeForPath()` helpers, make method private.

# 1.2.2

Expand Down
Loading
Loading