Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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