Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Server-to-server authentication #1687

Merged
merged 31 commits into from
Aug 18, 2021
Merged

Conversation

pcapriotti
Copy link
Contributor

@pcapriotti pcapriotti commented Jul 28, 2021

This is the final bit of logic implementing server-to-server authentication, namely validation of the domain name provided as part of the request against the certificate checked at the point of SSL termination.

Checklist

  • The PR Title explains the impact of the change.
  • The PR description provides context as to why the change should occur and what the code contributes to that effect. This could also be a link to a JIRA ticket or a Github issue, if there is one.
  • If end-points have been added or changed: the endpoint / config-flag checklist (see Wire-employee only backend wiki page) has been followed.
  • If a schema migration has been added, I ran make git-add-cassandra-schema to update the cassandra schema documentation.
  • Section Unreleased of CHANGELOG.md contains the following bits of information:
    • A line with the title and number of the PR in one or more suitable sub-sections.
    • If /a: measures to be taken by instance operators.
    • If /a: list of cassandra migrations.
    • If public end-points have been changed or added: does nginz need upgrade?
    • If internal end-points have been added or changed: which services have to be deployed in a specific order?

@pcapriotti pcapriotti changed the base branch from develop to pcapriotti/client-certificates July 28, 2021 15:44
@pcapriotti pcapriotti force-pushed the pcapriotti/s2s-authentication branch from 5f27c3e to da706ca Compare July 28, 2021 15:52
Copy link
Contributor

@mdimjasevic mdimjasevic left a comment

Choose a reason for hiding this comment

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

So far it looks quite good.

services/federator/src/Federator/ExternalServer.hs Outdated Show resolved Hide resolved
services/federator/src/Federator/Validation.hs Outdated Show resolved Hide resolved
exampleCert <- liftIO $ BS.readFile "test/resources/unit/localhost.pem"
let cfg =
(grpcClientConfigSimple (Text.unpack fedHost) (fromIntegral fedPort) False)
{ _grpcClientConfigHeaders = [("X-SSL-Certificate", exampleCert)]
Copy link
Contributor

Choose a reason for hiding this comment

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

It crossed my mind, but I am not completely sure about this: should the headers list be expanded here rather than replaced?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The default is empty, so it makes no difference here.

Comment on lines 43 to 46
mockDiscoveryTrivial :: Sem (DiscoverFederator ': r) x -> Sem r x
mockDiscoveryTrivial = Polysemy.interpret $ \(DiscoverFederator dom) ->
pure . Right $ SrvTarget (Text.encodeUtf8 (domainText dom)) 443
Copy link
Contributor

Choose a reason for hiding this comment

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

Given that this function is copy-pasted in ExternalServer.hs, how about moving it to a Util or Interpret module?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've now imported it from the other module directly.

@akshaymankar akshaymankar force-pushed the pcapriotti/s2s-authentication branch from da706ca to 39feecd Compare July 29, 2021 16:33
@pcapriotti pcapriotti force-pushed the pcapriotti/s2s-authentication branch 3 times, most recently from 8b6c767 to 5e4819b Compare August 2, 2021 06:49
@pcapriotti pcapriotti force-pushed the pcapriotti/client-certificates branch from d0f7f06 to 9b56467 Compare August 3, 2021 08:56
@pcapriotti pcapriotti force-pushed the pcapriotti/s2s-authentication branch from a67ab9a to 084453d Compare August 4, 2021 07:28
@pcapriotti pcapriotti force-pushed the pcapriotti/client-certificates branch from 78bdb9b to 24aa191 Compare August 9, 2021 10:13
@pcapriotti pcapriotti force-pushed the pcapriotti/s2s-authentication branch from 084453d to 5f83da7 Compare August 9, 2021 10:25
@pcapriotti pcapriotti marked this pull request as ready for review August 10, 2021 08:06
Base automatically changed from pcapriotti/client-certificates to develop August 16, 2021 13:33
pcapriotti and others added 15 commits August 17, 2021 12:27
This will be used for federator integration tests
This adds the same configuration option used for the demo nginx to the
nginx ingress.
This is used to set the originDomain field in federated requests within
federator integration tests. It cannot be set to a fixed canned value
like "example.com", because federators make SRV requests to perform
server-to-server authentication, so the domain must be something whose
DNS server contains an appropriate SRV record, and so it needs to be set
differently according to whether the test is running in the local "demo"
environment (where we have a tiny DNS server for "example.com"), or in
the CI integration setup, where we can rely on kubernetes DNS server for
the federation ingress host.
Copy link
Member

@jschaul jschaul 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 seems to make use of a new coreDNS pod, at least there's new config for that used in Run.hs; that's cool to be able to integration test DNS issues.

How do these integration tests work on kubernetes though? Also, I see lots of unit tests but no new integration tests. So where is the coreDNS pod actually used? It would be useful to add some comments in the integration tests that make use of DNS which provide some explanation how DNS is used during discovery for A) local integration tests and B) kubernetes integration tests (I assume some implict DNS names are created by some k8s service that match the name in some config file somewhere in the tests?); as issues arising here at some point in the future may not be easy to figure out.

As for documentation: some guidance how to configure federator and nginx-ingress helm charts for operators so that client certificates are made use of (do we allow server2server authentication to actually be turned off? I suppose we should not?) would be nice (in this or a follow-up PR), and some guidance on how to include your friendly backend's CA in your trust chain would be nice.

As for tests, can we test with a few more scenarios of certificates? E.g. expired, certificate chains of more than one,

services/federator/test/unit/Test/Federator/Validation.hs Outdated Show resolved Hide resolved
Comment on lines 170 to 172
case res of
Left (InwardError IAuthenticationFailed _) -> pure ()
x -> assertFailure $ "expected IAuthenticationFailed error, got " <> show x
Copy link
Member

Choose a reason for hiding this comment

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

maybe create a little helper function similar to expectErr in this file to not duplicate these three lines of case statements for expected errors?

Copy link
Member

Choose a reason for hiding this comment

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

I just replaced this with asserting more precisely on the errors.

@akshaymankar
Copy link
Member

This PR seems to make use of a new coreDNS pod, at least there's new config for that used in Run.hs; that's cool to be able to integration test DNS issues.

How do these integration tests work on kubernetes though? Also, I see lots of unit tests but no new integration tests. So where is the coreDNS pod actually used? It would be useful to add some comments in the integration tests that make use of DNS which provide some explanation how DNS is used during discovery for A) local integration tests and B) kubernetes integration tests (I assume some implict DNS names are created by some k8s service that match the name in some config file somewhere in the tests?); as issues arising here at some point in the future may not be easy to figure out.

With this PR, all the federated requests (even those which bypass nginx, i.e. federator integration tests) need the DNS entry for the origin domain to work. This is not a problem in kubernetes because, as you guessed, there is always an SRV record for the currently deployed federator, so we can just use that to make a request. For local development, however, we don't get this SRV record, so we first considered creating a global record, but decided it was ugly and brittle. So, we chose to just install coredns in our docker-ephmeral setup to facilitate this. The DNS name used by the integration tests is configured in charts/federator/templates/tests/configmap.yaml and services/integration.yaml.

We didn't need more integration tests because all integration tests started needing to provide this cert and all the failure cases were tested in unit test. But I think it would be nice to add one integration test where federation is denied due to wrong certificate would be good.

As for documentation: some guidance how to configure federator and nginx-ingress helm charts for operators so that client certificates are made use of (do we allow server2server authentication to actually be turned off? I suppose we should not?) would be nice (in this or a follow-up PR), and some guidance on how to include your friendly backend's CA in your trust chain would be nice.

Yes, we could certainly do a better job at documenting this. Let's take it up right after we merge this.

As for tests, can we test with a few more scenarios of certificates? E.g. expired, certificate chains of more than one,

We don't check expiry or even the chains. This is done by nginx. We could add integration tests, but I think it is ok to just trust nginx here.

@akshaymankar akshaymankar merged commit 19285b1 into develop Aug 18, 2021
@akshaymankar akshaymankar deleted the pcapriotti/s2s-authentication branch August 18, 2021 14:26
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.

None yet

4 participants