Skip to content

Commit ad46b85

Browse files
committed
docs: add mTLS setup tutorial
Add a tutorial detailing how to set up an mTLS-authenticated bundle server. Include a link to the 'docs/tutorials' directory in the repository root 'README.md' to clearly guide users to those resources. Helped-by: Derrick Stolee <[email protected]> Signed-off-by: Victoria Dye <[email protected]>
1 parent 222f0ac commit ad46b85

File tree

3 files changed

+178
-0
lines changed

3 files changed

+178
-0
lines changed

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,11 @@ server, you can manage the web server process itself using these commands:
152152
Finally, if you want to run the web server process directly in your terminal,
153153
for debugging purposes, then you can run `git-bundle-web-server`.
154154

155+
### Additional resources
156+
157+
Detailed guides to more complex administration tasks or user workflows can be
158+
found in the [`docs/tutorials`](./docs/tutorials/) directory of this repository.
159+
155160
## Local development
156161

157162
### Building

docs/tutorials/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Tutorials
2+
3+
This directory contains a series of in-depth tutorials regarding administration
4+
and usage of the bundle server.

docs/tutorials/mtls.md

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
# Configuring mTLS authentication for the web server
2+
3+
[Mutual TLS (mTLS)][mtls] is a mechanism for mutual authentication between a
4+
server and client. Configuring mTLS for a bundle server allows a server
5+
maintainer to limit bundle server access to only the users that have been
6+
provided with a valid certificate and establishes confidence that users are
7+
interacting with a valid bundle server.
8+
9+
[mtls]: https://www.cloudflare.com/learning/access-management/what-is-mutual-tls/
10+
11+
## mTLS limitations
12+
13+
mTLS in the bundle server is configured **server-wide**, so it only provides
14+
only a limited layer of protection against unauthorized access. Importantly,
15+
**any** user with a valid client cert/private key pair will be able to access
16+
**any** content on the bundle server. The implications of this include:
17+
18+
- If the bundle server manages repositories with separately controlled access,
19+
providing a user with a valid client cert/key for the bundle server may
20+
accidentally grant read access to Git data the user is not authorized to
21+
access on the remote host.
22+
- If the remote host has branch-level security then the bundles may contain Git
23+
objects reachable from restricted branches.
24+
25+
## Creating certificates
26+
27+
mTLS connections involve the verification of two X.509 certificates: one from
28+
the server, the other from the client. These certificates may be "self-signed",
29+
or issued by a separate certificate authority; either will work with the bundle
30+
server.
31+
32+
For both the server and client(s), both a public certificate (`.pem` file) and a
33+
private key must be generated. Self-signed pairs can easily be generated with
34+
OpenSSL; for example:
35+
36+
```bash
37+
openssl req -x509 -newkey rsa:4096 -days 365 -keyout cert.key -out cert.pem
38+
```
39+
40+
The above command will prompt the user to create a password for the 4096-bit RSA
41+
private key stored in `cert.key` (for no password, use the `-nodes` option),
42+
then fill in certificate metadata including locality information, company, etc.
43+
The resulting certificate - stored in `cert.pem` - will be valid for 365 days.
44+
45+
> :rotating_light: If the "Common Name" of the server certificate does not match
46+
> the bundle web server hostname (e.g. `localhost`), connections to the web
47+
> server may fail.
48+
49+
If instead generating a certificate signed by a certificate authority (which can
50+
itself be a self-signed certificate), a private key and _certificate signing
51+
request_ must first be generated:
52+
53+
```bash
54+
openssl req -new -newkey rsa:4096 -days 365 -keyout cert.key -out cert.csr
55+
```
56+
57+
The user will be prompted to fill in the same certificate metadata (`-nodes` can
58+
again be used to skip the password requirement on the private key). Once the
59+
request is generated (in `cert.csr`), the request can be signed with the CA (in
60+
the following example, with public certificate `ca.pem` and private key
61+
`ca.key`):
62+
63+
```bash
64+
openssl x509 -req -in cert.csr -CA ca.pem -CAkey ca.key -out cert.pem
65+
```
66+
67+
This generates the CA-signed certificate `cert.pem`.
68+
69+
### :rotating_light: IMPORTANT: PROTECTING YOUR CREDENTIALS :rotating_light:
70+
71+
It is _extremely_ important that the private keys associated with the generated
72+
certificates are safeguarded against unauthorized access (e.g. in a password
73+
manager with minimal access).
74+
75+
If the server-side key is exposed, a malicious site could pose as a valid bundle
76+
server and mislead users into providing it credentials or other private
77+
information. Potentially-exposed server credentials should be replaced as soon
78+
as possible, with the appropriate certificate authority/self-signed cert (_not_
79+
the private key) distributed to users that use the server.
80+
81+
If a client-side key is exposed, an unauthorized user or malicious actor will
82+
gain access to the bundle server and all content contained within it. **The
83+
bundle server does not provide a mechanism for revoking certificates**, so
84+
credentials will need to be rolled depending on how client certificates were
85+
generated:
86+
87+
- If the `--client-ca` used by the bundle web server is a self-signed
88+
certificate corresponding to a single client, a new certificate/key pair will
89+
need to be generated and the bundle web server restarted[^1] to use the new
90+
`--client-ca` file.
91+
- If the `--client-ca` is a concatenation of self-signed client certificates,
92+
the compromised certificate will need to be removed from the file and the
93+
bundle web server restarted.
94+
- If the `--client-ca` is a certificate authority (a single certificate used to
95+
sign other certificates), the certificate authority and _all_ client
96+
certificates will need to be replaced.
97+
98+
## Configuring the web server
99+
100+
To configure the web server, three files are needed:
101+
102+
- If using self-signed client certificate(s), the client certificate `.pem`
103+
(which may contain one or multiple client certificates concatenated together)
104+
_or_ the certificate authority `.pem` used to sign client certificate(s). In
105+
the example below, this is `ca.pem`.
106+
- The server `.pem` certificate file. In the example below, this is
107+
`server.pem`.
108+
- The server private key file. In the example below, this is `server.key`.
109+
110+
The bundle server can then be configured with the `web-server` command to run in
111+
the background:
112+
113+
```bash
114+
git-bundle-server web-server start --force --port 443 --cert server.pem --key server.key --client-ca ca.pem
115+
```
116+
117+
Alternatively, the web server can be started directly:
118+
119+
```bash
120+
git-bundle-web-server --port 443 --cert server.pem --key server.key --client-ca ca.pem
121+
```
122+
123+
If the contents of any of the certificate or key files change, the web server
124+
process must be restarted. To reload the background web server daemon, run
125+
`git-bundle-server web-server stop` followed by `git-bundle-server web-server
126+
start`.
127+
128+
## Configuring Git
129+
130+
If cloning or fetching from the bundle server via Git, the client needs to be
131+
configured to both verify the server certificate and send the appropriate client
132+
certificate information. This configuration can be applied using environment
133+
variables or `.gitconfig` values. The required configuration is as follows:
134+
135+
| Config (Environment) | Value |
136+
| --- | --- |
137+
| [`http.sslVerify`][sslVerify] (`GIT_SSL_NO_VERIFY`) | `true` for config, `false` for environment var. |
138+
| [`http.sslCert`][sslCert] (`GIT_SSL_CERT`) | Path to the `client.pem` public cert file. |
139+
| [`http.sslKey`][sslKey] (`GIT_SSL_KEY`) | Path to the `client.key` private key file. |
140+
| [`http.sslCertPasswordProtected`][sslKeyPassword] (`GIT_SSL_CERT_PASSWORD_PROTECTED`) | `true` |
141+
| [`http.sslCAInfo`][sslCAInfo] (`GIT_SSL_CAINFO`) | Path to the certificate authority file, including the server self-signed cert _or_ CA.[^2] |
142+
| [`http.sslCAPath`][sslCAPath] (`GIT_SSL_CAPATH`) | Path to the directory containing certificate authority files, including the server self-signed cert _or_ CA.[^2] |
143+
144+
Configuring the certificate authority information, in particular, can be tricky.
145+
Git does not have separate `http` configurations for clones/fetches vs. bundle
146+
URIs; both will use the same settings. As a result, if cloning via HTTP(S) with
147+
a bundle URI, users will need to _add_ the custom bundle server CA to the system
148+
store. The process for adding to the system certificate authorities are
149+
platform-dependent; for example, Ubuntu uses the
150+
[`update-ca-certificates`][update-ca-certificates] command.
151+
152+
To avoid needing to add the bundle server CA to the trusted CA store, users can
153+
instead choose to clone via SSH. In that case, only the bundle URI will use the
154+
`http` settings, so `http.sslCAInfo` can point directly to the standalone server
155+
CA.
156+
157+
[sslVerify]: https://git-scm.com/docs/git-config#Documentation/git-config.txt-httpsslVerify
158+
[sslCert]: https://git-scm.com/docs/git-config#Documentation/git-config.txt-httpsslCert
159+
[sslKey]: https://git-scm.com/docs/git-config#Documentation/git-config.txt-httpsslKey
160+
[sslKeyPassword]: https://git-scm.com/docs/git-config#Documentation/git-config.txt-httpsslCertPasswordProtected
161+
[sslCAInfo]: https://git-scm.com/docs/git-config#Documentation/git-config.txt-httpsslCAInfo
162+
[sslCAPath]: https://git-scm.com/docs/git-config#Documentation/git-config.txt-httpsslCAPath
163+
[update-ca-certificates]: https://manpages.ubuntu.com/manpages/xenial/man8/update-ca-certificates.8.html
164+
165+
[^1]: If using the `git-bundle-server web-server` command _and_ using a
166+
different `--client-ca` path than the old certificate, the `--force` option
167+
must be used with `start` to refresh the daemon configuration.
168+
[^2]: These settings are passed to cURL internally, setting `CURLOPT_CAINFO` and
169+
`CURLOPT_CAPATH` respectively.

0 commit comments

Comments
 (0)