Skip to content

Conversation

@arber-salihi
Copy link

Optional claims-based authorization for private deployments

Summary

This pull request adds optional claims-based authorization functionality to Fulcio, enabling organizations with private deployments to implement fine-grained access control policies based on OIDC token claims. This feature addresses the need for basic authorization in private deployments to avoid generating certificates blindly for any valid OIDC token issued by a configured OIDC Issuer. The public Sigstore instance does not need this functionality as it serves the broader community.

Authorization operates as an additional security layer after successful OIDC authentication and before certificate issuance. When enabled, configurable regex-based rules evaluate authenticated token claims to determine if a certificate request should be approved.

Resolves: #1989

Key features

  • Optional and backward compatible: No impact on existing deployments (authorization is only active when rules are configured)
  • Claims-based access control: Flexible rule system based on OIDC token claims
  • AND/OR logic support: Rules can combine multiple conditions with configurable logic
  • Performance optimized: Regex patterns are pre-compiled at startup for minimal runtime overhead
  • Auditability: Comprehensive logging, audit trail available

Configuration example

oidc-issuers:
  https://token.actions.githubusercontent.com:
    issuer-url: https://token.actions.githubusercontent.com
    client-id: sigstore
    type: github-workflow
    authorization-rules:
      - name: "Production repositories of myorg"
        logic: "AND"
        conditions:
          - field: "repository_owner"
            pattern: "^myorg$"
          - field: "repository"
            pattern: "^myorg/(api|web|mobile)$"
      - name: "Admin override"
        logic: "AND"
        conditions:
          - field: "actor"
            pattern: "^myorg-admin-bot$"

Implementation details

  • Authorization interface: pkg/authorization/authorizer.go - Core authorization logic with configurable rule evaluation
  • Configuration extension: pkg/config/config.go - Extends OIDC issuer configuration with authorization rules
  • Server integration: pkg/server/grpc_server.go - Integrates authorization into certificate issuance flow
  • Startup setup: cmd/app/grpc.go, cmd/app/serve.go - Rule compilation and authorizer initialization

Documentation updates

  • docs/authorization.md: Added feature documentation
  • docs/how-certificate-issuing-works.md: Updated workflow documentation
  • docs/oidc.md: Updated OIDC configuration guide
  • docs/security-model.md: Updated security model with authorization

All necessary documentation updates are contained within the files modified in this repository, and no updates to official external documentation are required for this feature.

Testing

  • Previous tests: All existing tests continue to pass
  • Unit tests: Added test coverage for authorization logic
  • Integration tested: Verified with real GitHub OIDC tokens
  • Error scenarios: Tested authorization failures, invalid configurations
  • Backward compatibility: Verified existing functionality unchanged

Backward compatibility

  • Backward compatible: Existing deployments continue working without changes
  • Optional feature: Feature is only active when authorization rules are configured
  • API unchanged: Client integration remains identical

Security considerations

  • No new attack vectors: Authorization only restricts access, doesn't expand it
  • ReDoS protection: Uses Go's safe regex implementation
  • Audit trail: All decisions logged for security monitoring
  • Fail-secure by design: Invalid authorization configuration prevents server startup (malformed rules never default to allow-all access)

Release notes

**Optional claims-based authorization for private deployments**

Organizations running private instances can now configure authorization rules to restrict certificate issuance based on OIDC token claims. This enables fine-grained access control policies without impacting existing deployments.

Authorization is completely optional and backward compatible: existing installations continue to work without any configuration changes.

Remarks

Beyond the comprehensive unit test coverage included in this pull request, we have tested this authorization feature locally using a local Fulcio server with real GitHub OIDC tokens obtained from actual GitHub Actions workflows. The core authorization logic added here is also currently deployed and operational in a non-production environment, where it runs through Envoy filters as an interim solution while awaiting the merge of this pull request. We have not observed any particular performance impact or operational issues.

We want to emphasize our deliberate design choice regarding malformed authorization rules: the server will fail to start if authorization rules are configured but some are malformed. This fail-secure approach ensures that misconfigured rules never default to allow-all access. While we acknowledge that an alternative approach could allow the server to start and simply ignore malformed rules with warning messages, we strongly recommend against this behavior as it could lead to unintended security gaps where administrators might not notice that their intended restrictions are not being enforced.

@arber-salihi arber-salihi requested a review from a team as a code owner August 24, 2025 12:30
This pull request adds optional claims-based authorization functionality to Fulcio, enabling organizations with private deployments to implement fine-grained access control policies based on OIDC token claims. This feature addresses the need for basic authorization in private deployments to avoid generating certificates blindly for any valid OIDC token issued by a configured OIDC Issuer. The public Sigstore instance does not need this functionality as it serves the broader community.

Authorization operates as an additional security layer after successful OIDC authentication and before certificate issuance. When enabled, configurable regex-based rules evaluate authenticated token claims to determine if a certificate request should be approved.

Resolves: sigstore#1989
Signed-off-by: Arbër Salihi <[email protected]>
@arber-salihi arber-salihi force-pushed the authorization-for-private-deployments branch from 446ffe0 to d733fda Compare August 24, 2025 12:31
Copy link
Contributor

@haydentherapper haydentherapper left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR is duplicative and quite complex, we have support for parsing a mapping of claim name to value already in https://github.com/sigstore/fulcio/blob/main/pkg/identity/ciprovider/principal.go. I'd suggest refactoring this existing code and reusing it here rather than introducing the same logic again.

Before continuing on this, please engage on the issue, proposing the changes you'd plan to make and get maintainer and issue submitter buy-in.

@arber-salihi
Copy link
Author

Hey @haydentherapper,

Thank you for the feedback! You're absolutely right about the duplication in claims parsing logic between pkg/identity/ciprovider/principal.go and the current implementation. I can definitely refactor to reuse the existing getTokenClaims() function to eliminate this redundancy.

That said, I want to clarify that the authorization feature extends significantly beyond claims parsing. The implementation includes rule evaluation with AND/OR logic and support for multiple conditions per rule – two aspects organizations typically would require for their private deployments.

Furthermore, this approach directly implements the regex-based validation suggested in issue #1989. While the original discussion focused on applying checks to subjects, implementing rules across all claims is more natural and effective
for real authorization scenarios. If we take the example of GitHub, organizations typically need to filter on repository_owner, repository, actor, and other attributes, and extending to all claims doesn't increase complexity.

Regarding complexity concerns, the implementation preserves full backward compatibility with zero impact when not configured, while providing straightforward rule definition for certificate request verification. The logic itself follows a clear pattern that should be familiar to operators already working with claim-based systems.

Note that the authorization logic is designed to work consistently across all OIDC issuer types, though GitHub Actions and similar CI providers remain the primary use cases where organizations would typically deploy these rules.

For the refactoring approach, I propose extracting and reusing the existing function for claims parsing while keeping authorization-specific logic such as rule evaluation and validation separate from shared components. This maintains clear separation of concerns between parsing and authorization functionality.

Does this refactoring approach address your duplication concerns while maintaining the authorization functionality? If you envision a different approach for this feature, I'd be interested to hear your thoughts on how you'd prefer to see it structured.

P.-S.: I'll also update issue #1989 to reference this discussion so the author of the issue can follow along and provide their feedback on the proposed implementation.

@haydentherapper
Copy link
Contributor

includes rule evaluation with AND/OR logic

If this is needed by an organization, I would recommend running a proxy in front of the CA. Supporting a minimal policy layer, such as "is this token from my org", is sufficient for most use cases.

I'm good with the feature supporting token claims, not just subject. We already have a mapping from token claim to CI claim, as seen in

extension-templates:
. What I'm suggesting here is to reuse
type Extensions struct {
and the related code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

issuance: Authenticate certificate requests based on OIDC token claims

2 participants