OAI / OpenAPI-Specification

The OpenAPI Specification Repository
https://openapis.org
Apache License 2.0
28.79k stars 9.07k forks source link

[OpenAPI.Next Proposal] Add client certificate to authentication methods #1004

Closed jimfox closed 4 years ago

jimfox commented 7 years ago

Use of client certificate for authn is very popular and support is ubiquitous.

khazelton commented 7 years ago

There are a number of client/service interactions where this would be a good choice. In particular this fits when the security requirements can be met by mutual authentication of client and server.

tobilarscheid commented 6 years ago

I vote for this, we have some real world use cases where we would like to use something like this. Also, this feature has already been proposed but than somehow got ignored: https://github.com/OAI/OpenAPI-Specification/issues/451#issuecomment-135856998

One thing though that from my point of view requires consideration: When I talk about "client certificate authentication" I typically mean a client presenting a certificate during the TLS handshake and the server granting or denying access based on that (as in rfc5264#section-7.4.6) This is not part of any HTTP interaction at all, it's actually one OSI-Layer lower. There is now two points of view that you could take:

I personally take the realist's view.

Still, it will be somewhat hard to cramp a TLS based client certificate authentication into the existing Security Scheme Object - this one is heavily based on HTTP. Smartest solution I see for now is adding another type and making all the other fields optional for it. As for the name of this new type I am not really sure what is the standard name for client certificates in the TLS handshake, I have read mTLS (for mutual TLS) in some contexts, but never really in RFCs. Also, the term mutual makes it somewhat confusable with mutual HTTP authentication - a whole different story. I therefore propose to simply name the type tls - the authentication is based on TLS. Users might then want to use the description to state the requirements for the cert, but this is optional as servers typically send a list of accepted CAs during the handshake (rfc5246#section-7.4.4).

A typical client certificate security definition would therefore then look like this:

{
   "type": "tls",
   "description": "Cert must be signed by evilcorp.com CA"
}
type: tls
description: Cert must be signed by evilcorp.com CA
cmheazel commented 6 years ago

Concur. I have a number of customers who require TLS with client certificates. If we don't add it to OpenAPI I'll have to write an extension. Better to have it as part of the spec.

MikeRalphson commented 6 years ago

@cmheazel thanks for the additional data-point. As per #1466 this request is under consideration for OAS 3.1

fterpstra commented 6 years ago

Within the Dutch public sector we have identified this requirement as well. b.t.w. @cmheazel nice to see you here as well ;)

bourgpa commented 6 years ago

We also plan to implement a REST API service for EU Customs & Taxations IAM system between European Commision and member states. In that case, it is far more easier for us to use two-way SSL as it is already the case for the SOAP WS already exposed. But for the moment my major problem is the lack of implementation at server-side. I had to switch back to Swager 2.0 api because of that. I hope that a 3.0 implementation will come soon, but I have doubt that the 3.1 will met my dead lines. Do we have an idea when 3.1 specifications will be frozen?

arnoudquanjer commented 6 years ago

@tobilarscheid I support your realist view. The Dutch municipalities are aiming to convert/replace their current monolithic information systems with an API-first software landscape, fulfilling societal demand for automation, transparency and privacy. To facilitate this we are setting up an open source inter-organisational system facilitating federated authentication, secure connecting and protocolling in a large-scale, dynamic API landscape. In this landscape we want to use two-way TLS.

MikeRalphson commented 6 years ago

On the subject of TLS client certificate authentication, as a straw man, would the following be sufficient to indicate that the client MUST provide a TLS certificate?

components:
  securitySchemes:
    clientCert:
      type: clientTLS
      serverSelfSigned: true

The default value of serverSelfSigned would be false. A true value would indicate that the client MUST accept self-signed certificates from the server.

Client-side tools would be free to identify or prompt for the relevant certificate using any means they wish.

tobilarscheid commented 6 years ago

Hi @MikeRalphson, thanks for your input. The solution looks like a good first step to me. However I do not quiet understand the emphasis on serverSelfSigned - why would that be something so important to include it here right away?

bourgpa commented 6 years ago

Hello,

I agree. Moreover, self-signed certificates are not used in production environements.

If you want to put more information useful for the client side, you could optionally list the CA certificates or URL of CA or eIDAS / alternate LOTL (for European Union) that are trusted for an 2 WAY SSL authentification with this service. But it should only be informative.

Pascal

On 15 May 2018 at 09:55, tobilarscheid notifications@github.com wrote:

Hi @MikeRalphson https://github.com/MikeRalphson, thanks for your input. The solution looks like a good first step to me. However I do not quiet understand the emphasis on serverSelfSigned - why would that be something so important to include it here right away?

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/OAI/OpenAPI-Specification/issues/1004#issuecomment-389077541, or mute the thread https://github.com/notifications/unsubscribe-auth/AiSLQN7RoFEVJbRJioNpVCP_r5vMt_-_ks5tyonbgaJpZM4MmFhZ .

MikeRalphson commented 6 years ago

@tobilarscheid @bourgpa re: self-signed certificates, this is completely up for debate, and is potentially an unwanted feature / in the wrong place, but I wanted to bring up the subject.

Moreover, self-signed certificates are not used in production environements.

This, unfortunately. is not the case in my experience. When an organisation manages their own CA, they sometimes issue self-signed certificates both for servers and clients. They may also have a place in microservice environments.

Personally, my feeling is that we should not list CAs, root certificates, CNs, or tread on the toes of TLS's negotiation of ciphers etc by including this information, but we are open to all use-cases and perspectives regarding this feature.

tobilarscheid commented 6 years ago

When an organisation manages their own CA, they sometimes issue self-signed certificates both for servers and clients. They may also have a place in microservice environments.

It really does not matter for security who signed the certificate as long as you trust the signee - on the other hand accepting a certificate that is signed by someone you don't trust / know is typically a bad idea. Because of this I deem the flag unnecessary / even misleading.

Personally, my feeling is that we should not list CAs, root certificates, CNs, or tread on the toes of TLS's negotiation of ciphers etc by including this information, but we are open to all use-cases and perspectives regarding this feature.

You are right that this is part of the TLS handshake already. Might still be nice to include just for informational purpose, but that could be something that can live in a comment field or the like as well IMHO.

MikeRalphson commented 6 years ago

@tobilarscheid

It really does not matter for security who signed the certificate as long as you trust the signee - on the other hand accepting a certificate that is signed by someone you don't trust / know is typically a bad idea. Because of this I deem the flag unnecessary / even misleading.

It may matter to the client's authentication libraries, which often must be passed a flag to disable the checking for self-signed certificates.

You are right that this is part of the TLS handshake already. Might still be nice to include just for informational purpose, but that could be something that can live in a comment field or the like as well IMHO.

Indeed, specification extensions / the new draft features approach may be a way to make this extensible.

tobilarscheid commented 6 years ago

It may matter to the client's authentication libraries, which often must be passed a flag to disable the checking for self-signed certificates.

that's what I say you should never do and specifically should not be promoted by this standard here.

MikeRalphson commented 6 years ago

that's what I say you should never do and specifically should not be promoted by this standard here.

I understand your concern, but allowing the description of a particular API implementation is not necessarily promoting it. cf. cookie parameters. The OAS is a specification for describing APIs, not a standard or a set of best-practices. My intention in including it was so this issue got debated.

cmheazel commented 6 years ago

We may be making this harder than it has to be. TLS runs below HTTP on the protocol stack. The scope of an OpenAPI document, and the software processing it, is not likely to extend to that level. So anything the OAS document has to say about TLS client certificates is informative. A Security Requirement Object of: { "authentication:ietf:5246:client_certificate": [] }
may be sufficient. The only impact this will have on the OAS specification is that we would have to: a) allow Security Requirements that do not map to a Security Schem or b) allow more values in the type field of the Security Scheme objects or c) both a and b. Option B may also be useful for implementing the cryptographic extension discussed a couple weeks ago.

darrelmiller commented 6 years ago

@cmheazel If docs tools are going to implement "try it" functionality against servers that are in a dev environment where certs are self-signed, they are going to need to know to turn off any cert validation.

MikeRalphson commented 6 years ago

@cmheazel

b) allow more values in the type field of the Security Scheme objects or

As above, this is the option we're discussing.

cmheazel commented 6 years ago

Sorry, I miss-read the example. This relates to issue #1552

cmheazel commented 6 years ago

@darrelmiller But is that in-scope for OAS? In my experience, client side certificates are configured once and never modified. Any changes required for a dev environment are passed out of band.

ioggstream commented 6 years ago

@bourgpa I have similar requirements too (always for public administrations).

@MikeRalphson what do you think of using the more general x509 reference?

components:
  securitySchemes:
    clientCert:
      type: x509
MikeRalphson commented 6 years ago

@ioggstream fair question. All TLS communication uses x509 certificates, but we probably want to make it clear that for this type of securityScheme the client must additionally present a certificate (in the above example clientCert is an arbitrary identifier, and could be anything). Perhaps to disambiguate any future client certificate types and to indicate the x509 certificate should have the Client Authentication extended key usage, we could use x509client or similar?

cmheazel commented 6 years ago

Perhaps we should introduce security scheme types for both TLS and TLS_Mutual_Authentication. This makes it clear that the client certificate is being used within the context of the TLS protocol. This is probably a good time to dust off the crypto extension proposal.

MikeRalphson commented 6 years ago

Perhaps we should introduce security scheme types for both TLS and TLS_Mutual_Authentication

How does this square with your earlier comment

TLS runs below HTTP on the protocol stack. The scope of an OpenAPI document, and the software processing it, is not likely to extend to that level. So anything the OAS document has to say about TLS ... is informative

? TLS usage is a function of the server in use for communication and does not directly relate to the OAS concept of security.

This is probably a good time to dust off the crypto extension proposal.

Not directly in this issue, I feel. That is a much bigger change and focuses on one particular approach to crypto. I expect @isamauny and other interested parties to comment here if this particular proposal conflicts with the crypto extension proposal.

cmheazel commented 6 years ago

@MikeRalphson I made my point. Since the consensus seems to be that TLS-level security is in scope for OAS, we move on. What I'm trying to avoid here is a point solution. If we are going to support one optional TLS capability, then we should do it in a way that is extensible.

cmheazel commented 6 years ago

@MikeRalphson I agree that crypto is a separate issue. But it is related and should be coordinated.

ioggstream commented 6 years ago

Hi @MikeRalphson, and thanks for your time!

we probably want to make it clear that for this type of securityScheme the client must additionally present a certificate [...] with the Client Authentication extended key usage Fair. The goal is to support future definitions based on x509 (eg. SSL -> TLS -> ULS -> WLS ;) )

components:
  securitySchemes:
    clientCert:
      type: x509client

@simo5 could it be ok for that case? https://github.com/openshift/origin/pull/14745#discussion-diff-123263482R683

@darrelmiller not sure that we can manage to always tryit with mutal-tls. The server should be willing to accept an untrusted cert too. We could just provide something in the swagger-ui for that, but not in the spec.

simo5 commented 6 years ago

@ioggstream our intent is to only convey what authentications schemes are accepted, and mTLS is one of them. Note that a server will never accept an untrusted cert, but also that you do not have to use a client cert, mTLS can be optional, if you come with a cert you are implicitly authenticated (or not, depending on configuration) at the HTTP layer, if you come without a cert then you are just anonymous.

ioggstream commented 6 years ago

@simo5 thx for your reply!

our intent is to only convey what authentications schemes are accepted, and mTLS is one of them.

Sure: do you think the above spec proposal x509client will cover your use case?

Note that a server will never accept an untrusted cert

Sure: that's why I said that the specs shouldn't tell anything on trust (see https://github.com/OAI/OpenAPI-Specification/issues/1004#issuecomment-389184421)

mTLS can be optional, [..] if you come without a cert then you are just anonymous.

afaik OpenAPI allows multiple securitySchemes, eg

components:
  securitySchemes:
    clientCert:
      type: x509client
    BasicAuth:
      type: http
      scheme: basic

@MikeRalphson iiuc https://github.com/OAI/OpenAPI-Specification/issues/14#issuecomment-297457320 says the following, right?

paths:
  /ping:
    get:
      summary: Checks if the server is running
      # Both unauthenticated and x509client
      security:
      - 
      - x509client
    ...
MikeRalphson commented 6 years ago

how do you specify a path with both anonymous and clientCert?

The syntax is non-obvious (and we have previously solicited PRs to make it clearer / provide an example in spec), but providing optional security requirements is explained in this comment (which it has taken me :rage: amount of time to locate):

https://github.com/OAI/OpenAPI-Specification/issues/14#issuecomment-297457320

pleothaud commented 6 years ago

@simo5 : some servers will definitely accept untrusted certificates (ssl_verify_client optional_no_ca in NGINX conf or SSLVerifyClient optional_no_ca in Apache conf, for example). It means that you don't want to use TLS for Authentication but only for integrity and confidentiality of exchanged messages. There are a few use-cases for that, specially when you already convey Authentication information using another mechanism.

pleothaud commented 6 years ago

It could be nice to add two Security Scheme Object types, x509client to require client certificate based mTLS AuthN and none, to solve elegantly the "both anonymous and clientCert" problem.

MikeRalphson commented 6 years ago

@pleothaud

It could be nice to add [...] none, to solve elegantly the "both anonymous and clientCert" problem.

none would just be another way of writing

security:
- {}

and though it may be clearer, the OAS currently favours a more Pythonic ("There should be one - and preferably only one - obvious way to do it")* approach rather than a Perl-style TMTOWTDI approach.

* For some value of "obvious".

simo5 commented 6 years ago

@pleothaud from the POV of the securityScheme, that is equivalent to not specifying x509client at all. We care for exposing a x509 Certificate label only if the client can use a cert to authenticate.

pleothaud commented 6 years ago

@simo5 from the POV of securityScheme (and hence AuthN) you're right, but for the POV of the ability to consume the API you have to express that the client will have to provide a client certificate to be able to connect.

This is why in addition to the AuthN related requirements (expressed in the Security Scheme, Security Requirement objects and finally in the security fixed field of the Operation object), we should be able to express constraints at the Server object level.

These constraints should express at least:

If a client certificate is required or accepted we should have in addition:

WDYT?

pleothaud commented 6 years ago

Such an extension to the Server object plus the addition of a x509client Security Scheme Object types would allow to express all combinations of mTLS optional or required, as well as mixing operations requiring no authentication, some other requiring Basic or OAuth only and others requiring mTLS (potentially in addition to Basic or OAuth)

pleothaud commented 6 years ago

If clientCertificateRequired is required, the Security Requirement stating that an x509client Security Scheme is required to consume a specific Operation will be redundant information (as mTLS AuthN is in this case sort of a side effect of Transport level TLS configuration) but it will anyway be more readable for developers, IMHO

pleothaud commented 6 years ago

@MikeRalphson I'd never dare to say that Perl is more elegant than Python ;-)

simo5 commented 6 years ago

@pleothaud I do not think it makes sense to notify whether the server certificate is self-signed or not. Either the client trusts it or it doesn't, the server doesn't get to tell the client "I am self signed TRUST me".

Servers need to accept connections w/o client certificates (otherwise you can't even get the OpenAPI definitions without prior knowledge). I am not sure that it makes any sense to advertize the server accepts self-signed but untrusted client certs, it has no purpose.

If the server advertizes that it accepts x509client authentication, then a client can try to use the certs it has, if all of them fail it can try to fallback to non cert based auth. The client can autodetect if a server accepts untrusted certificates [because the connection will go through the TLS layer but requests will fail as unauthenticated as opposed to fail at the TLS connection layer], so the client can decide whether it wants to use a client cert or not; from the POV of a server it makes no sense to require an untrusted client cert as it provides no additional security.

So I am definitely against codifying any option that hints at accepting untrusted certificates, as it is useless from a security POV and/or can be simply probed by the client.

pleothaud commented 6 years ago

@simo5

  1. In dev environment it is very frequent that you use a quickly made self-signed cert on a server and in this case you don't want to bother to export/import the cert in your client's keystore to do the testing, so you check the "don't verify server cert" box and make your tests. This is just about making developers life easy during the iterative dev/test process (and making developers life easy is key to the adoption of the standard!).

2.a. OAS files can be retrieved by other means than an HTTP(S) request 2.b. OAS files can be retrieved for instance from an API developer portal (or any other kind of repo) and then do not have to be retrieved on the backend server exposing directly the API

I'm not sure your assertion that an API backend cannot require a client certificate at TLS level for the whole server can be accepted in any high security environment.

  1. Once again, you may want to use TLS for other reasons than mTLS based AuthN. Client certificate can for instance be verified at the application level and not at the transport level, by some other mechanisms than your TLS stack (see for an example of that the 2.2. paragraph of Self-Signed Certificate Mutual TLS OAuth Client Authentication Method of the OAuth 2.0 Mutual TLS Client Authentication and Certificate Bound Access Tokens at https://tools.ietf.org/html/draft-ietf-oauth-mtls-08#page-6). Please note that accepting client self-signed certificates mandates that you use optional_no_ca, and in this case the client MUST use a client certificate to establish the TLS tunnel. And so we should advertise that in the OAS file.

I personnally don't like neither the use of untrusted certificates but in the end it exists, for some good or bad reasons... As they say, "be liberal in what you accept" otherwise you block adoption.

simo5 commented 6 years ago

@pleothaud I understand the use case for (1), but it is simply misguided.

A client can never trust a server to tell it to lower all security, otherwise that client is broken by definition (as it can be told the same when in production). Therefore advertizing anything of the sort is simply useless, the developer still need to actively tell the client it is ok to trust an untrusted server. It is therefore something that a server has no reason to advertize to start with.

ok on (2).

On (3) please do not mix TLS with PKI and/or x509 certs, these 3 technologies are inter-related but not mutually interchangeable concepts.

In that oauth drafta a very contrived method is used to postpone validation of certificates to the application layer. But this simply means that the server is not doing mTLS, it is just accepting connnections where clients happen to present an untrusted client certificate and then the server also allows the application to request data on that certificate. This kind of authentication need to be advertized in a different way via a specific oauth+x509cert label or similar, it has nothing to do with regular x509client and should not be mixed in here.

The point is, you can use untrusted certificates, but it makes no sense for a server to advertize it explicitly, because there is nothing the client can do and nothing the client should do. Either the client has certs to use or it doesn't, either the client trusts the server cert or it doesn't, nothing the server will say about the trustworthiness of certs matters.

ioggstream commented 6 years ago

@pleothaud imho

@MikeRalphson @simo5 if we all agree at least on this model we could make an RFE and push for that.

components:
  securitySchemes:
    clientCert:
      type: x509client
      # We are still free to add stuff here.
    BasicAuth:
      type: http
      scheme: basic

paths:
  /ping:
    get:
      summary: Both unauthenticated and x509client
      security:
      - {}
      - clientCert: []
    ...
    post:
      summary:  >-
        Only with x509client. The server (un)trust configuration shouldn't be in the contract as it may
          vary between different environments. The API shouldn't vary b/w dev/test/prod.
      security:
      - clientCert: []
simo5 commented 6 years ago

@ioggstream sounds reasonable to me

darrelmiller commented 6 years ago

@ioggstream I think your example should have said...

   security:
      - {}
      - clientCert

Security Requirement objects reference the key of the security scheme.

ioggstream commented 6 years ago

@darrelmiller thx++ Fixed (see above).

cmheazel commented 6 years ago

Final sanity check, is the security scheme type sufficiently unambiguous? 1) Might there be a case where we are using X.509 client certs but not over TLS? 2) Might there be a case where the TLS client cert is not X.509? 3) Is there a case where a client certificate is used that is neither TLS nor X.509? 4) Are there other variants we may have missed? Keep in mind that we are still running code written 30 years ago. Plan for the future.

simo5 commented 6 years ago

I guess you could call it TLSClientCertificate, and avoid all of the above questions.

ioggstream commented 6 years ago

@cmheazel imho:

  1. it's the old SSL
  2. TLS peer certificate is x509v3 https://tools.ietf.org/html/rfc5246#section-7
  3. I suggest to rephrase the issue "Support authentication based on x509 certificates".
  4. Nothing you can't specify in scheme ;)

    • if we disambiguate with TLSClientCertificate then a newer spec (eg. ULS ;) ) means a rename. I'd rather use a scheme.
  securitySchemes:
    clientCert:
      type: x509client
      spec: tls   #  or rfc5246|mtls|whatever
cmheazel commented 6 years ago

@ioggstream You win the prize.

MikeRalphson commented 6 years ago

Thank you everyone for the comments - I'm still going through them. I hope to be able to summarise where we're at in time for the next TSC meeting on June 4th.

Just a note @darrelmiller and @ioggstream :

security:
-

does not mean the same as

security:
- {}

An empty definition in YAML is shorthand for null, not the empty object, as is required to indicate a none security requirement.

Final sanity check, is the security scheme type sufficiently unambiguous?

@cmheazel The unambiguity will be addressed by the spec. defining its terms (i.e. what it means by tlsClientCert or whatever type value we agree on). What we're primarily seeking is clarity.

@ioggstream: scheme is a term with a defined meaning in RFC7235 - which effectively defines a subtype of http authentication, 'Scheme' in TLS seems generally to be used with regard to "signature schemes". Even if we are defining a subtype here I think we should avoid the term 'scheme'. If we are in fact defining a supertype, then we probably have our type value wrong.