Skip to content

Conversation

@pcapriotti
Copy link
Contributor

@pcapriotti pcapriotti commented Jul 26, 2021

This adds support for client authentication using TLS certificates when making requests to a remote backend.

Summary of changes

  • Added new configuration options for client certificate and private key
  • Configured demo nginz to require client certificates
  • Read client certificate on federator startup
  • Use client certificate when creating a GRPC client
  • Upgrade haskell packages tls and cryptonite
  • Add script to serve helm charts in a repository running at http://localhost:4001

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.
  • New configuration options have been documented
  • 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 certificates-improvements July 26, 2021 07:09
Base automatically changed from certificates-improvements to develop July 27, 2021 07:53
@pcapriotti pcapriotti force-pushed the pcapriotti/client-certificates branch 2 times, most recently from 99719ea to 775ab37 Compare July 28, 2021 06:14
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.

I know this is still marked as draft, but I had a look already anyway and made a few suggestions.

@pcapriotti pcapriotti marked this pull request as ready for review July 30, 2021 05:41
Copy link
Member

@akshaymankar akshaymankar left a comment

Choose a reason for hiding this comment

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

Can you please explain whey we have/need let's encrypt staging? Otherwise, the PR looks good.

@pcapriotti
Copy link
Contributor Author

Can you please explain whey we have/need let's encrypt staging? Otherwise, the PR looks good.

I thought we could merge it with staging first to see whether things have been configured correctly. Or we could deploy it (and cert-manager) on the CI environment and check if things work there. If you think it's ok to use production immediately, I can of course change it.

@akshaymankar
Copy link
Member

Can you please explain whey we have/need let's encrypt staging? Otherwise, the PR looks good.

I thought we could merge it with staging first to see whether things have been configured correctly. Or we could deploy it (and cert-manager) on the CI environment and check if things work there. If you think it's ok to use production immediately, I can of course change it.

I think it makes sense to try all of this out with staging cert manager first, but to do that we already have certificate-manager.apiServerURL config.

server: {{ include "certificate-manager.apiServerURL" . | quote }}

@pcapriotti
Copy link
Contributor Author

I think it makes sense to try all of this out with staging cert manager first, but to do that we already have certificate-manager.apiServerURL config.

But we would also need to set the CA to use, since that's different between staging and production.

@akshaymankar
Copy link
Member

I think it makes sense to try all of this out with staging cert manager first, but to do that we already have certificate-manager.apiServerURL config.

But we would also need to set the CA to use, since that's different between staging and production.

Yes, but we shouldn't need to hardcode the CA into our code. We can make the testing person set that in the values.yaml when they are deploying the charts.

@pcapriotti pcapriotti force-pushed the pcapriotti/client-certificates branch from d0f7f06 to 9b56467 Compare August 3, 2021 08:56
Use the same issuer for both certificates. Whether we are using Let's
Encrypt staging or production is determined by `certManager.inTestMode`
so we don't need a separate issuer to enable staging.
It seems cert-manager takes control of the `ca.crt` key in the secret
corresponding to a certificate, so it does not seem possible to set it
manually when cert-manager is enabled. Unfortunately, it still needs to
be a secret, since the ingress requires it.

This commit moves the CA to a separate secret. Therefore, it needs to be
set explicitly in the chart values for both federator and the
nginx-ingress-services, even if federator secret sharing is enabled.
federator-ca is a configmap, not a secret
@pcapriotti pcapriotti force-pushed the pcapriotti/client-certificates branch from 78bdb9b to 24aa191 Compare August 9, 2021 10:13
Copy link
Member

@akshaymankar akshaymankar left a comment

Choose a reason for hiding this comment

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

Overall looks good, I am not clear on why the client cert is optional.

@akshaymankar akshaymankar merged commit a706a5c into develop Aug 16, 2021
@akshaymankar akshaymankar deleted the pcapriotti/client-certificates branch August 16, 2021 13:33
@jschaul
Copy link
Member

jschaul commented Aug 17, 2021

Post-merge review: Looks good overall. Few minor questions came to mind:

  1. What was your usecase for the serve-helm-charts-locally script? Which part of the development flow was this useful for?
  2. I see client certificates seem to be optional in the federator configuration, as well as in the config options readme to an operator. Wouldn't the remote backend just reject all requests if there's no valid client certificate passed though? The configuration in the nginx-ingress seems to always turn client certificate validation "on" if I read this correctly (whatever that means; shouldn't this reject the http request if it doesn't contain a client cert?). Perhaps the config-options readme could get an extra line informing a non-backend-engineer server admin on when to provide a client certificate and when this isn't necessary, and what the effects are of not specifying this.

@jschaul
Copy link
Member

jschaul commented Aug 17, 2021

One more thought: the useSharedFederatorSecret setting in the federator (or wire-server) helm chart ties the federator/wire-server helm chart to the nginx-ingress-services helm chart. Yet currently those are installed separately. Is there an ordering concern here? Can I install wire-server with this setting to true before nginx-ingress-controller is installed? Or would I need to first install nginx-ingress-services before I can install wire-server helm chart?
In case there is an ugly ordering concern, can we resolve it by including the nginx-ingress-controller chart as part of wire-server's requirements (see https://github.com/wireapp/wire-server/blob/develop/charts/wire-server/requirements.yaml) ?

@akshaymankar
Copy link
Member

What was your usecase for the serve-helm-charts-locally script? Which part of the development flow was this useful for?

We wanted to deploy the code in this branch to an environment using wire-server-deploy, but we couldn't without either pushing the charts to some repository or serving them locally. The newly created adhoc-testing environment can use this by adding http://localhost:4001 to its repositories list.

I see client certificates seem to be optional in the federator configuration, as well as in the config options readme to an operator. Wouldn't the remote backend just reject all requests if there's no valid client certificate passed though?

This is a mistake, they were originally optional, but then we realized they shouldn't be. There is no way the federator could work without them. So, the docs in config-options needed update and we forgot.

The configuration in the nginx-ingress seems to always turn client certificate validation "on" if I read this correctly (whatever that means; shouldn't this reject the http request if it doesn't contain a client cert?).

Yes, setting it to always turn "on" will make any requests without a client cert to be rejected.

Perhaps the config-options readme could get an extra line informing a non-backend-engineer server admin on when to provide a client certificate and when this isn't necessary, and what the effects are of not specifying this.

As said earlier, this is a mistake, I will rectify it by marking this as not optional.

One more thought: the useSharedFederatorSecret setting in the federator (or wire-server) helm chart ties the federator/wire-server helm chart to the nginx-ingress-services helm chart. Yet currently those are installed separately. Is there an ordering concern here? Can I install wire-server with this setting to true before nginx-ingress-controller is installed? Or would I need to first install nginx-ingress-services before I can install wire-server helm chart?

If someone turns useSharedFederatorSecret to true, it means that secret must exist before wire-server can be deployed. The secret doesn't have to come from the nginx-ingress-services, it can come from anywhere, for instance someone having their own TLS acquiring mechanism. But I guess in most cases, the operators would want to deploy nginx-ingress-services before wire-server.

In case there is an ugly ordering concern, can we resolve it by including the nginx-ingress-controller chart as part of wire-server's requirements (see https://github.com/wireapp/wire-server/blob/develop/charts/wire-server/requirements.yaml) ?

This is not good, if we want the ingress-controller business to be optional. This is similar to how deploying wire-server requires cassandra, elasticsearch, etc to be there. But we don't want to mandate that people use our given cassandra and elasticsearch. So, we already have this ordering problem and I guess we solve it by making sure all our docs tell users to install those things before wire-server. Currently, it is not the case with ingress-controller and services, so I will make that change to our docs.

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.

4 participants