Skip to content

Encode conditional security for endpoints #301

@jwulf

Description

@jwulf

Surfaced via #277.

The securitySchemes annotation is related to camunda/camunda#52511.

Currently, the security annotation has not been added to OCA API endpoints that are secured at runtime when the server is started with security enabled.

I think the reason they have not been applied is because they are conditional on deployment mode. Claude calls this the "security posture" of the server.

  • A c8ctl user starting the Camunda Run distribution encounters an API that never returns 401 or 403.
  • A developer interacting with SaaS or SM started with authentication/authorization encounters an API that does.

So declaring the API as either of these in incorrect in one of the cases. Thus, we've opted to drop annotating it. It's "undefined".

OpenAPI has a gap — it assumes a fixed posture.

We need this information for test planning.

I think the information belongs in the specification itself. The reason for this is that it is directly correlated with the implementation — in the sense that if we were to purely generate the API, we would use the signal to wrap the generated endpoint with authentication/authorization machinery based on the specification.

Crucially, it would be conditionally turned on or off depending on the runtime mode of the server. We need a way to encode this is the specification for both the implementation generator and the test planner.

There are various parts to this:

  1. Encoding
  • A TBox level declaration of deployment modes — security posture is one instance of a broader concern. Another example would be OIDC mode (integration or external-provider).
  • An ABox level declaration of a security mode.
  • A way to encode in the specification that an endpoint has a securitySchema and under which condition it is active.
  1. Consumption
  • We need to run tests against secured and unsecured server modes. So we would emit two directories: tests generated for a secured server and tests for an unsecured server. If we generalise this, we would also emit in the same way for any instance of a deployment mode axis: eg: integrated and external OIDC modes. This would generalise into a matrix: we would emit a complete suite with the combination of all ABox deployment modes — eg: secured | unsecured x oidc-integrated | oidc-external x ...... t=(t1​,t2​,…,tn​)where ti​∈Di​.
  • A separate runner configuration would use the ontology to reason about the how to start the server with the correct configuration and run the correct test suite for the configuration.

In the specification, we use vendor extensions (ABox) with custom vocabularies (TBox) to model things that OpenAPI can't express.

In this case, Claude naively suggests something like:

paths:
  /resource:
    get:
      security:
        - bearerAuth: []
      x-security-optional: true  # auth bypassed when server runs in unsecured mode

OpenAPI securitySchemes is a TBox-level declaration of the security vocabulary for an endpoint. The security annotation on an endpoint is an ABox assertion. Adding this optionality to it makes it a defeasible assertion. One that holds by default but can be overridden by specific conditions. It's related to "defeatible". It can be defeated, or dismantled, by a context.

If we adopted this approach, we would have to add the optionality to every endpoint, but that's the wrong level. We should extend OpenAPI's TBox to encode optionality, like this:

components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      x-enforcement: conditional
      x-enforcement-modes:
        secured: required
        unsecured: none

Then just add the security annotation to all operational endpoints that can be secured. Our reasoners will read it as conditionally secured based on the expanded TBox via vendor extensions.

This seems like the right level of abstraction: we add the TBox vocabulary for "conditional enforcement" and "enforcement modes".

If we later find out that there are modes that differentially secure endpoints, we can extend the TBox further and update the ABox on the affected endpoints.

This gives the test planner the information that it would need to reason about endpoint security and test assertions (plan for tests that will get 401). To integrate it, we would need to then extend the planner TBox to be able to reason about the assertions in the specification, and make sure that camunda-schema-bundler passes them through to the test planner for consumption.

401 vs 403 will need more modelling, but my instinct is that this would be in the test planner.

@esraagamal6, I suggest that we divide this one up like this:

  1. You discuss the design of x-enforcement and x-enforcement-modes with Copilot to see how this intersects with the TBox and ABox ontologies in the test planner and Encode deployment-mode availability as a first-class axis of the semantic graph camunda#52511 to see if this is the right level of abstraction. If it is, you extend the OpenAPI spec with this and add the security annotation to the (conditionally) secured endpoints.
  2. I'll make sure that camunda-schema-bundler correctly passes this metadata to the test planner.

How does that sound?

This covers encoding, then we tackle consumption as the next step. With an open PR in camunda/camunda with the updated OpenAPI specification, we can build tests from the branch to test it before merging it to main.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions