From 0625d6d735b828127a5871a1981100efb3a5c928 Mon Sep 17 00:00:00 2001 From: Rahul Vishwakarma Date: Wed, 10 Dec 2025 23:59:57 +0530 Subject: [PATCH 1/4] feat(policy): add witness policy generate command Signed-off-by: Rahul Vishwakarma --- cmd/config_test.go | 0 cmd/policy.go | 73 +++++++- cmd/policy_generate.go | 403 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 475 insertions(+), 1 deletion(-) create mode 100644 cmd/config_test.go create mode 100644 cmd/policy_generate.go diff --git a/cmd/config_test.go b/cmd/config_test.go new file mode 100644 index 00000000..e69de29b diff --git a/cmd/policy.go b/cmd/policy.go index ea50bc4d..c31bf9a9 100644 --- a/cmd/policy.go +++ b/cmd/policy.go @@ -14,7 +14,9 @@ package cmd -import "github.com/spf13/cobra" +import ( + "github.com/spf13/cobra" +) // PolicyCmd has several subcommands for managing policies func PolicyCmd() *cobra.Command { @@ -24,10 +26,48 @@ func PolicyCmd() *cobra.Command { } cmd.AddCommand( PolicyCheckCmd(), + PolicyGenerateCmd(), ) return cmd } +type PolicyGenerateOptions struct { + StepNames []string + RootCAs []string + PublicKeys []string + Intermediates []string + AttestationTypes []string + // RegoPolicies []string + CertCommonName []string + CertDNSNames []string + CertEmails []string + CertOrgs []string + CertURIs []string + ArtifactsFrom []string + ExpiresIn string + OutputFile string +} + +func PolicyGenerateCmd() *cobra.Command { + vo := PolicyGenerateOptions{} + cmd := &cobra.Command{ + Use: "generate", + Short: "Generate a policy file", + Long: ` +Example: + witness policy generate --step "build" --step "deploy" --root-ca "build=rootCA.pem" --root-ca "deploy=deployCA.pem" --public-key "build=buildKey.pub" --public-key "deploy=deployKey.pub"`, + SilenceErrors: true, + SilenceUsage: true, + DisableAutoGenTag: true, + RunE: func(cmd *cobra.Command, args []string) error { + return generatePolicy(cmd, &vo) + }, + } + vo.AddFlags(cmd) + + return cmd +} + // PolicyValidateCmd validates a policy func PolicyCheckCmd() *cobra.Command { cmd := &cobra.Command{ @@ -49,3 +89,34 @@ func PolicyCheckCmd() *cobra.Command { return cmd } + +func (vo *PolicyGenerateOptions) AddFlags(cmd *cobra.Command) { + cmd.Flags().StringSliceVar(&vo.StepNames, "step", []string{}, + "Name of a step to include in the policy (can be specified multiple times)") + cmd.Flags().StringSliceVar(&vo.RootCAs, "root-ca", []string{}, + "Root CA certificate in format 'step=file.pem' (can be specified multiple times)") + cmd.Flags().StringSliceVar(&vo.PublicKeys, "public-key", []string{}, + "Public key in format 'step=file.pub' (can be specified multiple times)") + cmd.Flags().StringSliceVar(&vo.Intermediates, "intermediate", []string{}, + "Intermediate certificate in format 'step=file.pem' (can be specified multiple times)") + cmd.Flags().StringSliceVar(&vo.AttestationTypes, "attestation", []string{}, + "Attestation type in format 'step=type-url' (can be specified multiple times)") + // cmd.Flags().StringSliceVar(&vo.RegoPolicies, "rego-policy", []string{}, + // "Rego policy in format 'step=name=file.rego' (can be specified multiple times)") + cmd.Flags().StringSliceVar(&vo.CertCommonName, "cert-cn", []string{}, + "Certificate common name constraint in format 'step=commonname'") + cmd.Flags().StringSliceVar(&vo.CertDNSNames, "cert-dns", []string{}, + "Certificate DNS name constraint in format 'step=dnsname'") + cmd.Flags().StringSliceVar(&vo.CertEmails, "cert-email", []string{}, + "Certificate email constraint in format 'step=email'") + cmd.Flags().StringSliceVar(&vo.CertOrgs, "cert-org", []string{}, + "Certificate organization constraint in format 'step=organization'") + cmd.Flags().StringSliceVar(&vo.CertURIs, "cert-uri", []string{}, + "Certificate URI constraint in format 'step=uri' (useful for SPIFFE IDs)") + cmd.Flags().StringSliceVar(&vo.ArtifactsFrom, "artifacts-from", []string{}, + "Artifact dependency in format 'step=fromStep' (can be specified multiple times)") + cmd.Flags().StringVar(&vo.ExpiresIn, "expires-in", "720h", + "Duration until policy expires (e.g., '720h' for 30 days, '8760h' for 1 year)") + cmd.Flags().StringVarP(&vo.OutputFile, "output", "o", "policy.json", + "Output file path for the generated policy") +} diff --git a/cmd/policy_generate.go b/cmd/policy_generate.go new file mode 100644 index 00000000..f4f79c1e --- /dev/null +++ b/cmd/policy_generate.go @@ -0,0 +1,403 @@ +// Copyright 2025 The Witness Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cmd + +import ( + "crypto/sha256" + "crypto/x509" + "encoding/base64" + "encoding/json" + "encoding/pem" + "fmt" + "os" + "strings" + "time" + + "github.com/in-toto/go-witness/attestation" + "github.com/in-toto/go-witness/log" + "github.com/in-toto/go-witness/policy" + "github.com/spf13/cobra" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// generatePolicy generates a new policy file based on provided options +func generatePolicy(cmd *cobra.Command, opts *PolicyGenerateOptions) error { + log.Info("Generating Witness policy...") + + if len(opts.StepNames) == 0 { + return fmt.Errorf("at least one step must be specified with --step") + } + + expiresIn, err := time.ParseDuration(opts.ExpiresIn) + if err != nil { + return fmt.Errorf("invalid --expires-in duration '%s': %w", opts.ExpiresIn, err) + } + + pol := &policy.Policy{ + Expires: metav1.Time{Time: time.Now().Add(expiresIn)}, + Steps: make(map[string]policy.Step), + PublicKeys: make(map[string]policy.PublicKey), + Roots: make(map[string]policy.Root), + TimestampAuthorities: make(map[string]policy.Root), + } + + rootCAsByStep, err := parseStepMappedFlags(opts.RootCAs) + if err != nil { + return fmt.Errorf("failed to parse --root-ca flags: %w", err) + } + + publicKeysByStep, err := parseStepMappedFlags(opts.PublicKeys) + if err != nil { + return fmt.Errorf("failed to parse --public-key flags: %w", err) + } + + intermediatesByStep, err := parseStepMappedFlags(opts.Intermediates) + if err != nil { + return fmt.Errorf("failed to parse --intermediate flags: %w", err) + } + + attestationsByStep, err := parseAttestationFlags(opts.AttestationTypes) + if err != nil { + return fmt.Errorf("failed to parse --attestation flags: %w", err) + } + + certCNsByStep, err := parseStepMappedFlags(opts.CertCommonName) + if err != nil { + return fmt.Errorf("failed to parse --cert-cn flags: %w", err) + } + + certDNSByStep, err := parseStepMappedFlags(opts.CertDNSNames) + if err != nil { + return fmt.Errorf("failed to parse --cert-dns flags: %w", err) + } + + certEmailsByStep, err := parseStepMappedFlags(opts.CertEmails) + if err != nil { + return fmt.Errorf("failed to parse --cert-email flags: %w", err) + } + + certOrgsByStep, err := parseStepMappedFlags(opts.CertOrgs) + if err != nil { + return fmt.Errorf("failed to parse --cert-org flags: %w", err) + } + + certURIsByStep, err := parseStepMappedFlags(opts.CertURIs) + if err != nil { + return fmt.Errorf("failed to parse --cert-uri flags: %w", err) + } + + artifactsFromByStep, err := parseStepMappedFlags(opts.ArtifactsFrom) + if err != nil { + return fmt.Errorf("failed to parse --artifacts-from flags: %w", err) + } + + for _, stepName := range opts.StepNames { + log.Infof("Processing step: %s", stepName) + + step := policy.Step{ + Name: stepName, + Attestations: []policy.Attestation{}, + Functionaries: []policy.Functionary{}, + ArtifactsFrom: []string{}, + } + alwaysRunAttestors := []string{"material", "command-run", "product"} + addedAttestorTypes := make(map[string]bool) + + for _, attName := range alwaysRunAttestors { + attestor, err := attestation.GetAttestor(attName) + if err != nil { + log.Warnf("Failed to get always-run attestor '%s': %v", attName, err) + continue + } + + attType := attestor.Type() + attestation := policy.Attestation{ + Type: attType, + RegoPolicies: []policy.RegoPolicy{}, + } + + step.Attestations = append(step.Attestations, attestation) + addedAttestorTypes[attType] = true + } + + if attestationNames, ok := attestationsByStep[stepName]; ok { + for _, attName := range attestationNames { + + attestor, err := attestation.GetAttestor(attName) + if err != nil { + log.Error(err) + } + + attType := attestor.Type() + + if addedAttestorTypes[attType] { + log.Infof("Skipping attestation '%s' (type: %s) - already added as always-run attestor", attName, attType) + continue + } + + attestation := policy.Attestation{ + Type: attType, + RegoPolicies: []policy.RegoPolicy{}, + } + step.Attestations = append(step.Attestations, attestation) + addedAttestorTypes[attType] = true + } + } + + if pubKeyFiles, ok := publicKeysByStep[stepName]; ok { + for _, pubKeyFile := range pubKeyFiles { + keyID, pubKey, err := loadPublicKey(pubKeyFile) + if err != nil { + return fmt.Errorf("failed to load public key '%s' for step '%s': %w", pubKeyFile, stepName, err) + } + + pol.PublicKeys[keyID] = pubKey + step.Functionaries = append(step.Functionaries, policy.Functionary{ + Type: "publickey", + PublicKeyID: keyID, + }) + log.Debugf("Added public key functionary (keyid: %s) for step '%s'", keyID, stepName) + } + } + + if rootCAFiles, ok := rootCAsByStep[stepName]; ok { + for _, rootCAFile := range rootCAFiles { + keyID, root, err := loadRootCA(rootCAFile) + if err != nil { + return fmt.Errorf("failed to load root CA '%s' for step '%s': %w", rootCAFile, stepName, err) + } + + if intermediateFiles, ok := intermediatesByStep[stepName]; ok { + for _, intFile := range intermediateFiles { + intCert, err := loadIntermediateCert(intFile) + if err != nil { + return fmt.Errorf("failed to load intermediate '%s' for step '%s': %w", intFile, stepName, err) + } + root.Intermediates = append(root.Intermediates, intCert) + } + } + + pol.Roots[keyID] = root + certConstraint := policy.CertConstraint{ + CommonName: "*", + DNSNames: []string{"*"}, + Emails: []string{"*"}, + Organizations: []string{"*"}, + URIs: []string{"*"}, + Roots: []string{keyID}, + } + + if cns, ok := certCNsByStep[stepName]; ok && len(cns) > 0 { + certConstraint.CommonName = cns[0] + } + if dns, ok := certDNSByStep[stepName]; ok && len(dns) > 0 { + certConstraint.DNSNames = dns + } + if emails, ok := certEmailsByStep[stepName]; ok && len(emails) > 0 { + certConstraint.Emails = emails + } + if orgs, ok := certOrgsByStep[stepName]; ok && len(orgs) > 0 { + certConstraint.Organizations = orgs + } + if uris, ok := certURIsByStep[stepName]; ok && len(uris) > 0 { + certConstraint.URIs = uris + } + + step.Functionaries = append(step.Functionaries, policy.Functionary{ + Type: "root", + CertConstraint: certConstraint, + }) + + log.Debugf("Added root CA functionary (keyid: %s) for step '%s'", keyID, stepName) + } + } + + if artifacts, ok := artifactsFromByStep[stepName]; ok { + step.ArtifactsFrom = artifacts + log.Debugf("Step '%s' depends on artifacts from: %v", stepName, artifacts) + } + + if len(step.Functionaries) == 0 { + return fmt.Errorf("step '%s' has no functionaries (no --public-key or --root-ca specified)", stepName) + } + + pol.Steps[stepName] = step + } + + policyJSON, err := json.MarshalIndent(pol, "", " ") + if err != nil { + return fmt.Errorf("failed to marshal policy to JSON: %w", err) + } + + if err := os.WriteFile(opts.OutputFile, policyJSON, 0644); err != nil { + return fmt.Errorf("failed to write policy to '%s': %w", opts.OutputFile, err) + } + + log.Infof("Policy successfully generated: %s", opts.OutputFile) + log.Infof("Policy expires: %s", pol.Expires.Format(time.RFC3339)) + log.Infof("Steps: %d", len(pol.Steps)) + log.Infof("Public keys: %d", len(pol.PublicKeys)) + log.Infof("Root CAs: %d", len(pol.Roots)) + + return nil +} + +// parseStepMappedFlags parses flags in format "step=value" +func parseStepMappedFlags(flags []string) (map[string][]string, error) { + result := make(map[string][]string) + + for _, flag := range flags { + parts := strings.SplitN(flag, "=", 2) + if len(parts) != 2 { + return nil, fmt.Errorf("invalid format '%s': expected 'step=value'", flag) + } + + stepName := strings.TrimSpace(parts[0]) + value := strings.TrimSpace(parts[1]) + + if stepName == "" || value == "" { + return nil, fmt.Errorf("invalid format '%s': step name and value cannot be empty", flag) + } + + result[stepName] = append(result[stepName], value) + } + + return result, nil +} + +// parseAttestationFlags parses attestation flags in format "step=attestor_name" +// It resolves attestor names to their type URLs using the attestation registry +func parseAttestationFlags(flags []string) (map[string][]string, error) { + result := make(map[string][]string) + + for _, flag := range flags { + parts := strings.SplitN(flag, "=", 2) + if len(parts) != 2 { + return nil, fmt.Errorf("invalid attestation format '%s': expected 'step=attestor_name'", flag) + } + + stepName := strings.TrimSpace(parts[0]) + attestorName := strings.TrimSpace(parts[1]) + + if stepName == "" || attestorName == "" { + return nil, fmt.Errorf("invalid attestation format '%s': step name and attestor name cannot be empty", flag) + } + + _, err := attestation.GetAttestor(attestorName) + if err != nil { + return nil, fmt.Errorf("unknown attestor '%s' for step '%s': %w\nRun 'witness attestors list' to see available attestors", attestorName, stepName, err) + } + + result[stepName] = append(result[stepName], attestorName) + } + + return result, nil +} + +// loadPublicKey loads a public key from file and returns its key ID and policy.PublicKey +func loadPublicKey(filePath string) (string, policy.PublicKey, error) { + keyBytes, err := os.ReadFile(filePath) + if err != nil { + return "", policy.PublicKey{}, fmt.Errorf("failed to read public key file: %w", err) + } + + block, _ := pem.Decode(keyBytes) + if block == nil { + return "", policy.PublicKey{}, fmt.Errorf("failed to decode PEM block from public key file") + } + + _, err = x509.ParsePKIXPublicKey(block.Bytes) + if err != nil { + return "", policy.PublicKey{}, fmt.Errorf("failed to parse public key: %w", err) + } + + hash := sha256.Sum256(block.Bytes) + keyID := fmt.Sprintf("%x", hash) + + encodedKey := base64.StdEncoding.EncodeToString(keyBytes) + + return keyID, policy.PublicKey{ + KeyID: keyID, + Key: []byte(encodedKey), + }, nil +} + +// loadRootCA loads a root CA certificate and returns its key ID and policy.Root +func loadRootCA(filePath string) (string, policy.Root, error) { + certBytes, err := os.ReadFile(filePath) + if err != nil { + return "", policy.Root{}, fmt.Errorf("failed to read root CA file: %w", err) + } + + block, _ := pem.Decode(certBytes) + if block == nil { + return "", policy.Root{}, fmt.Errorf("failed to decode PEM block from root CA file") + } + + cert, err := x509.ParseCertificate(block.Bytes) + if err != nil { + return "", policy.Root{}, fmt.Errorf("failed to parse root CA certificate: %w", err) + } + + if !cert.IsCA { + return "", policy.Root{}, fmt.Errorf("certificate is not a CA certificate (CA:FALSE)") + } + + if time.Now().After(cert.NotAfter) { + return "", policy.Root{}, fmt.Errorf("certificate expired on %s", cert.NotAfter.Format(time.RFC3339)) + } + + pubKeyBytes, err := x509.MarshalPKIXPublicKey(cert.PublicKey) + if err != nil { + return "", policy.Root{}, fmt.Errorf("failed to marshal public key: %w", err) + } + hash := sha256.Sum256(pubKeyBytes) + keyID := fmt.Sprintf("%x", hash) + encodedCert := base64.StdEncoding.EncodeToString(certBytes) + + return keyID, policy.Root{ + Certificate: []byte(encodedCert), + Intermediates: [][]byte{}, + }, nil +} + +// loadIntermediateCert loads an intermediate certificate and returns it base64 encoded +func loadIntermediateCert(filePath string) ([]byte, error) { + certBytes, err := os.ReadFile(filePath) + if err != nil { + return nil, fmt.Errorf("failed to read intermediate certificate file: %w", err) + } + + block, _ := pem.Decode(certBytes) + if block == nil { + return nil, fmt.Errorf("failed to decode PEM block from intermediate certificate file") + } + + cert, err := x509.ParseCertificate(block.Bytes) + if err != nil { + return nil, fmt.Errorf("failed to parse intermediate certificate: %w", err) + } + + if !cert.IsCA { + return nil, fmt.Errorf("certificate is not a CA certificate (CA:FALSE)") + } + + if time.Now().After(cert.NotAfter) { + return nil, fmt.Errorf("certificate expired on %s", cert.NotAfter.Format(time.RFC3339)) + } + encodedCert := base64.StdEncoding.EncodeToString(certBytes) + + return []byte(encodedCert), nil +} From 5945e82b190c25d1dc118810dc1bd0aa210fdbde Mon Sep 17 00:00:00 2001 From: Rahul Vishwakarma Date: Tue, 16 Dec 2025 16:14:35 +0530 Subject: [PATCH 2/4] fix the --root-ca failed due to invalid PEM block Signed-off-by: Rahul Vishwakarma --- cmd/policy_generate.go | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/cmd/policy_generate.go b/cmd/policy_generate.go index f4f79c1e..e6c63aea 100644 --- a/cmd/policy_generate.go +++ b/cmd/policy_generate.go @@ -17,7 +17,6 @@ package cmd import ( "crypto/sha256" "crypto/x509" - "encoding/base64" "encoding/json" "encoding/pem" "fmt" @@ -156,6 +155,8 @@ func generatePolicy(cmd *cobra.Command, opts *PolicyGenerateOptions) error { } } + // TODO: add rego policies logic + if pubKeyFiles, ok := publicKeysByStep[stepName]; ok { for _, pubKeyFile := range pubKeyFiles { keyID, pubKey, err := loadPublicKey(pubKeyFile) @@ -323,14 +324,12 @@ func loadPublicKey(filePath string) (string, policy.PublicKey, error) { return "", policy.PublicKey{}, fmt.Errorf("failed to parse public key: %w", err) } - hash := sha256.Sum256(block.Bytes) + hash := sha256.Sum256(keyBytes) keyID := fmt.Sprintf("%x", hash) - encodedKey := base64.StdEncoding.EncodeToString(keyBytes) - return keyID, policy.PublicKey{ KeyID: keyID, - Key: []byte(encodedKey), + Key: keyBytes, }, nil } @@ -359,16 +358,13 @@ func loadRootCA(filePath string) (string, policy.Root, error) { return "", policy.Root{}, fmt.Errorf("certificate expired on %s", cert.NotAfter.Format(time.RFC3339)) } - pubKeyBytes, err := x509.MarshalPKIXPublicKey(cert.PublicKey) - if err != nil { - return "", policy.Root{}, fmt.Errorf("failed to marshal public key: %w", err) - } - hash := sha256.Sum256(pubKeyBytes) + hash := sha256.Sum256(certBytes) keyID := fmt.Sprintf("%x", hash) - encodedCert := base64.StdEncoding.EncodeToString(certBytes) + + // encodedCert := []byte(base64.StdEncoding.EncodeToString(certBytes)) return keyID, policy.Root{ - Certificate: []byte(encodedCert), + Certificate: certBytes, Intermediates: [][]byte{}, }, nil } @@ -397,7 +393,7 @@ func loadIntermediateCert(filePath string) ([]byte, error) { if time.Now().After(cert.NotAfter) { return nil, fmt.Errorf("certificate expired on %s", cert.NotAfter.Format(time.RFC3339)) } - encodedCert := base64.StdEncoding.EncodeToString(certBytes) + // encodedCert := []byte(base64.StdEncoding.EncodeToString(certBytes)) - return []byte(encodedCert), nil + return certBytes, nil } From 071b8bfb5486dfc7a653b6e700b4b5beb2b892df Mon Sep 17 00:00:00 2001 From: Rahul Vishwakarma Date: Tue, 16 Dec 2025 18:40:06 +0530 Subject: [PATCH 3/4] add docs for policy generate cmd Signed-off-by: Rahul Vishwakarma --- docs/commands.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/commands.md b/docs/commands.md index 9cd5932d..74e5a288 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -54,6 +54,7 @@ Manage policies * [witness](witness.md) - Collect and verify attestations about your build environments * [witness policy check](witness_policy_check.md) - Check a policy file +* [witness policy generate](witness_policy_generate.md) - Generate a policy file ## witness run @@ -108,6 +109,7 @@ witness run [cmd] [flags] --signer-fulcio-token string Raw token string to use for authentication to fulcio (cannot be used in conjunction with --fulcio-token-path) --signer-fulcio-token-path string Path to the file containing a raw token to use for authentication to fulcio (cannot be used in conjunction with --fulcio-token) --signer-fulcio-url string Fulcio address to sign with + --signer-fulcio-use-http HTTP/REST mode for Fulcio --signer-kms-aws-config-file string The shared configuration file to use with the AWS KMS signer provider --signer-kms-aws-credentials-file string The shared credentials file to use with the AWS KMS signer provider --signer-kms-aws-insecure-skip-verify Skip verification of the server's certificate chain and host name @@ -175,6 +177,7 @@ witness sign [file] [flags] --signer-fulcio-token string Raw token string to use for authentication to fulcio (cannot be used in conjunction with --fulcio-token-path) --signer-fulcio-token-path string Path to the file containing a raw token to use for authentication to fulcio (cannot be used in conjunction with --fulcio-token) --signer-fulcio-url string Fulcio address to sign with + --signer-fulcio-use-http HTTP/REST mode for Fulcio --signer-kms-aws-config-file string The shared configuration file to use with the AWS KMS signer provider --signer-kms-aws-credentials-file string The shared credentials file to use with the AWS KMS signer provider --signer-kms-aws-insecure-skip-verify Skip verification of the server's certificate chain and host name From 1a2ca8c5eb91f4fbc9d10872b029e4f7b9e5ba8f Mon Sep 17 00:00:00 2001 From: Rahul Vishwakarma Date: Tue, 16 Dec 2025 18:46:48 +0530 Subject: [PATCH 4/4] revert the unsual changes in docs Signed-off-by: Rahul Vishwakarma --- cmd/config_test.go | 0 docs/commands.md | 2 -- 2 files changed, 2 deletions(-) delete mode 100644 cmd/config_test.go diff --git a/cmd/config_test.go b/cmd/config_test.go deleted file mode 100644 index e69de29b..00000000 diff --git a/docs/commands.md b/docs/commands.md index 74e5a288..3f775dec 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -109,7 +109,6 @@ witness run [cmd] [flags] --signer-fulcio-token string Raw token string to use for authentication to fulcio (cannot be used in conjunction with --fulcio-token-path) --signer-fulcio-token-path string Path to the file containing a raw token to use for authentication to fulcio (cannot be used in conjunction with --fulcio-token) --signer-fulcio-url string Fulcio address to sign with - --signer-fulcio-use-http HTTP/REST mode for Fulcio --signer-kms-aws-config-file string The shared configuration file to use with the AWS KMS signer provider --signer-kms-aws-credentials-file string The shared credentials file to use with the AWS KMS signer provider --signer-kms-aws-insecure-skip-verify Skip verification of the server's certificate chain and host name @@ -177,7 +176,6 @@ witness sign [file] [flags] --signer-fulcio-token string Raw token string to use for authentication to fulcio (cannot be used in conjunction with --fulcio-token-path) --signer-fulcio-token-path string Path to the file containing a raw token to use for authentication to fulcio (cannot be used in conjunction with --fulcio-token) --signer-fulcio-url string Fulcio address to sign with - --signer-fulcio-use-http HTTP/REST mode for Fulcio --signer-kms-aws-config-file string The shared configuration file to use with the AWS KMS signer provider --signer-kms-aws-credentials-file string The shared credentials file to use with the AWS KMS signer provider --signer-kms-aws-insecure-skip-verify Skip verification of the server's certificate chain and host name