review shim docs authored by anarcat's avatar anarcat
The static/GitLab shim allows GitLab (CI) to push updates on websites The static/GitLab shim allows [GitLab CI][] to push updates on websites
hosted in the static mirror infrastructure. hosted in the [static mirror system][].
[[_TOC_]] [[_TOC_]]
...@@ -7,11 +7,11 @@ hosted in the static mirror infrastructure. ...@@ -7,11 +7,11 @@ hosted in the static mirror infrastructure.
## Deploying a static site from GitLab CI ## Deploying a static site from GitLab CI
First, you will need to make sure the site builds in [GitLab CI][]. A First, make sure the site builds in [GitLab CI][]. A `build` stage
`build` stage MUST be used that will produce artifacts that can be MUST be used. It should produce the artifacts used by the `deploy`
used by the `deploy` job provided in the [`static-shim-deploy.yml` job, provided in the [`static-shim-deploy.yml` template][]. How to
template][]. How to build the website will vary according to the site, build the website will vary according to the site, obviously. See the
obviously. See the [Hugo build instructions below](#building-a-hugo-site) for that [Hugo build instructions below](#building-a-hugo-site) for that
specific generator. specific generator.
[`static-shim-deploy.yml` template]: https://gitlab.torproject.org/tpo/tpa/ci-templates/-/blob/main/static-shim-deploy.yml [`static-shim-deploy.yml` template]: https://gitlab.torproject.org/tpo/tpa/ci-templates/-/blob/main/static-shim-deploy.yml
...@@ -72,6 +72,9 @@ Then the *public* part of that key needs to be added in Puppet. This ...@@ -72,6 +72,9 @@ Then the *public* part of that key needs to be added in Puppet. This
can only be done by TPA, so file a ticket there if you need can only be done by TPA, so file a ticket there if you need
assistance. For TPA, [see below](#adding-a-new-static-site-shim-in-puppet) for the remaining instructions. assistance. For TPA, [see below](#adding-a-new-static-site-shim-in-puppet) for the remaining instructions.
Once you have sent the public key to TPA, you MUST destroy your local
copy of the key, to avoid any possible future leaks.
You can commit the above changes to the `.gitlab-ci.yml` file, but You can commit the above changes to the `.gitlab-ci.yml` file, but
when pushed, the pipeline's `deploy` stage is normal, TPA needs to do when pushed, the pipeline's `deploy` stage is normal, TPA needs to do
its magic for the deploy to work. Make sure the build works in GitLab its magic for the deploy to work. Make sure the build works in GitLab
...@@ -139,18 +142,41 @@ it hasn't already been [migrated to GitLab](howto/gitlab#how-to-migrate-a-git-re ...@@ -139,18 +142,41 @@ it hasn't already been [migrated to GitLab](howto/gitlab#how-to-migrate-a-git-re
## Building a Hugo site ## Building a Hugo site
Normally, you should be able to deploy a hugo site by including the Normally, you should be able to deploy a hugo site by including the
template and setting a few variables. This `.gitlab-ci.yml` file template and setting a few variables. This `.gitlab-ci.yml` file,
should be sufficient: taken from the [status.tpo .gitlab-ci.yml](https://gitlab.torproject.org/tpo/tpa/status-site/-/blob/main/.gitlab-ci.yml), should be sufficient:
``` ```
include: image: registry.gitlab.com/pages/hugo/hugo_extended:0.65.3
project: tpo/tpa/ci-templates
file: static-shim-deploy.yml
variables: variables:
GIT_SUBMODULE_STRATEGY: recursive GIT_SUBMODULE_STRATEGY: recursive
SITE_URL: research.torproject.org SITE_URL: status.torproject.org
SUBDIR: public/ SUBDIR: public/
include:
project: tpo/tpa/ci-templates
file: static-shim-deploy.yml
build:
stage: build
script:
- hugo
artifacts:
paths:
- public
# we'd like to *not* rebuild hugo here, but pages fails with:
#
# jobs pages config should implement a script: or a trigger: keyword
pages:
stage: deploy
script:
- hugo
artifacts:
paths:
- public
only:
- merge_requests
``` ```
See below if this is an old hugo site, however. See below if this is an old hugo site, however.
...@@ -251,6 +277,8 @@ should provide more information. ...@@ -251,6 +277,8 @@ should provide more information.
## Disaster recovery ## Disaster recovery
### Server lost
The service is "cattle" in that it can easily be rebuilt from scratch The service is "cattle" in that it can easily be rebuilt from scratch
if the server is completely lost. Naturally it strongly depends on if the server is completely lost. Naturally it strongly depends on
GitLab for operation. If GitLab would fail, it should still be GitLab for operation. If GitLab would fail, it should still be
...@@ -264,6 +292,8 @@ The status site is particularly vulnerable to disasters here, see the ...@@ -264,6 +292,8 @@ The status site is particularly vulnerable to disasters here, see the
[status-site disaster recovery documentation](service/status#disaster-recovery) for pointers on where [status-site disaster recovery documentation](service/status#disaster-recovery) for pointers on where
to go in case things really go south. to go in case things really go south.
### GitLab server compromise
Another possible disaster that could happen is a complete GitLab Another possible disaster that could happen is a complete GitLab
compromise or hostile GitLab admin. Such an attacker could deploy any compromise or hostile GitLab admin. Such an attacker could deploy any
site they wanted and therefore deface or sabotage critical websites, site they wanted and therefore deface or sabotage critical websites,
...@@ -279,6 +309,11 @@ occur: ...@@ -279,6 +309,11 @@ occur:
3. redeploy the sites manually (`static-update-component $URL`) 3. redeploy the sites manually (`static-update-component $URL`)
The static shim server itself should be fairly immune to compromise as
only TPA is allowed to login over SSH, apart from the private keys
configured in the GitLab projects. And those are very restricted in
what they can do (ie. only `rrsync` and `static-update-component`).
# Reference # Reference
## Installation ## Installation
...@@ -314,16 +349,20 @@ component. ...@@ -314,16 +349,20 @@ component.
A [previous design](#webhook-deployment) involved a webhook written in Python, but now most A [previous design](#webhook-deployment) involved a webhook written in Python, but now most
of the business logic resides in a [`static-shim-deploy.yml` template] of the business logic resides in a [`static-shim-deploy.yml` template]
template which is basically a shell script embedded in a YAML template which is basically a shell script embedded in a YAML
file. The CI hooks are deployed by users, which will typically include file. (We have considered taking this out of the template and writing
the above template in their own `.gitlab-ci.yml` file. a proper Python script, but then users would have to copy that script
over their repo, or clone a repo in CI, and that seems impractical.)
The CI hooks are deployed by users, which will typically include the
above template in their own `.gitlab-ci.yml` file.
[static mirror system]: howto/static-component [static mirror system]: howto/static-component
### Storage ### Storage
Files are generated in GitLab CI as artifacts and stored there, which Files are generated in GitLab CI as artifacts and stored there, which
makes it possible for them to be deployed by hand as well. A copy is makes it possible for them to be [deployed by hand as well](#deploy-artifacts-manually). A copy
also kept on the static-shim server to make future deployments is also kept on the static-shim server to make future deployments
faster. We use `rsync --checksum` to avoid updating the timestamps faster. We use `rsync --checksum` to avoid updating the timestamps
even if the source file were just regenerated from scratch. even if the source file were just regenerated from scratch.
...@@ -333,7 +372,9 @@ The shim assumes that GitLab projects host a private SSH key and can ...@@ -333,7 +372,9 @@ The shim assumes that GitLab projects host a private SSH key and can
access the shim server over SSH with it. Access is granted, by Puppet access the shim server over SSH with it. Access is granted, by Puppet
(`tor-puppet.git` repository, `hiera/common.yaml` file, in the (`tor-puppet.git` repository, `hiera/common.yaml` file, in the
`staticsync::gitlab_shim::ssh::sites` hash) only to a specific `staticsync::gitlab_shim::ssh::sites` hash) only to a specific
site. The restriction occurs in the `authorized_keys` file, with site.
The restriction is defined in the `authorized_keys` file, with
`restrict` and `command=` options. The latter restricts the public key `restrict` and `command=` options. The latter restricts the public key
to only a *specific* site update, with a wrapper that will call to only a *specific* site update, with a wrapper that will call
`static-update-component` on the right component or `rrsync` which is `static-update-component` on the right component or `rrsync` which is
...@@ -349,7 +390,8 @@ The impact of this is that a compromise on GitLab or GitLab CI can ...@@ -349,7 +390,8 @@ The impact of this is that a compromise on GitLab or GitLab CI can
compromise all web sites managed by GitLab CI. While we do restrict compromise all web sites managed by GitLab CI. While we do restrict
what individual keys can do, a total compromise of GitLab could, in what individual keys can do, a total compromise of GitLab could, in
theory, leak all those private keys and therefore defeat those theory, leak all those private keys and therefore defeat those
mechanisms. mechanisms. See the [disaster recovery section](#disaster-recovery) for how such a
compromise could be recovered from.
The GitLab runners, in turn, authenticate the SSH server through a The GitLab runners, in turn, authenticate the SSH server through a
[instance-level CI/CD variable](https://docs.gitlab.com/ee/ci/variables/#add-a-cicd-variable-to-an-instance) called [instance-level CI/CD variable](https://docs.gitlab.com/ee/ci/variables/#add-a-cicd-variable-to-an-instance) called
...@@ -377,7 +419,7 @@ by all "critical" websites managed in GitLab. ...@@ -377,7 +419,7 @@ by all "critical" websites managed in GitLab.
## Monitoring and testing ## Monitoring and testing
There is not specific monitoring for this service, other than the There is no specific monitoring for this service, other than the
usual server-level monitoring. If the service should fail, users will usual server-level monitoring. If the service should fail, users will
notice because their pipelines start failing. notice because their pipelines start failing.
...@@ -434,8 +476,15 @@ retire the static mirror system (in favor, say, of GitLab Pages), we ...@@ -434,8 +476,15 @@ retire the static mirror system (in favor, say, of GitLab Pages), we
had to create a way for GitLab CI to deploy content to the static had to create a way for GitLab CI to deploy content to the static
mirror system. mirror system.
This section contains more in-depth discussions about the reasoning
behind the project, discarded alternatives, and other ideas.
## Goals ## Goals
Note that those goals were actually written down once the server was
launched, but they were established mentally before and during the
deployment.
### Must have ### Must have
* deploy sites from GitLab CI to the static mirror system * deploy sites from GitLab CI to the static mirror system
...@@ -455,7 +504,7 @@ mirror system. ...@@ -455,7 +504,7 @@ mirror system.
## Approvals required ## Approvals required
TPA TPA.
## Proposed Solution ## Proposed Solution
...@@ -468,9 +517,9 @@ One VM, 20-30 hours of work, see [tpo/tpa/team#40364](https://gitlab.torproject. ...@@ -468,9 +517,9 @@ One VM, 20-30 hours of work, see [tpo/tpa/team#40364](https://gitlab.torproject.
## Alternatives considered ## Alternatives considered
This shim was designed to replace Jenkins with GitLab CI. As suche, This shim was designed to replace Jenkins with GitLab CI. The various
other options were considered, see also the [Jenkins documentation](service/jenkins#gitlab-ci) options considered are discussed here, see also the [Jenkins
and [ticket 40364](https://gitlab.torproject.org/tpo/tpa/team/-/issues/40364) on those. documentation](service/jenkins#gitlab-ci) and [ticket 40364](https://gitlab.torproject.org/tpo/tpa/team/-/issues/40364).
### CI deployment ### CI deployment
... ...
......