Menshen
Menshen is a gateway & bridge distribution service for LEAP VPN.
In chinese folk religions, menshen are guardians of doors and gates.
Overview
menshen
is a resource distributor for LEAP VPN. Here, resource means
information for accessing either gateways, bridges, or a combination of the
two. This information includes not only endpoint discovery but also
crendentials (although the credential distribution is not fully integrated at
this point).
After adopting 002-vpnweb-deprecation,
menshen is responsible for centrally handling the resource inventory, and assigning each item on the
inventory to the users of the system. How this is assigned can change from deployment to deployment, but the
general idea is that menshen takes several parameters into account, including
current node capacity, geolocation, user preferences (i.e., opting-in to
resource marked as experimental) and possible ACLs in place.
Architecture
menshen
is a single service that is currently only bootstrapped with the
legacy service inventory information coming from vpnweb
(in the form of
eip-service.json
, remotely or from an in-disk file). As specified in 002-vpnweb-deprecation,
this is intended as a compatibility measure that will have to be phased out at some point.
menshen
also listens on an internal port where it receives information from
menshen_agent
running on each gateway via gRPC calls (receiving information
from bridges is TBD).
The auto-generated clients from the menshen spec are feeded to bitmask-core to
get clients compatible with the latest version of the spec.
graph
eip-service.json --> menshen
inventory -.-> menshen
menshen_agent_gw --lb--> menshen
menshen_agent_br -.-lb-.-> menshen
control_br -.-> menshen
control_gw -.-> menshen
subgraph "gateway"
menshen_agent_gw
control_gw
openvpn
end
subgraph "bridge"
menshen_agent_br
control_br
obfsvpn
end
menshen --> bitmask-core
In the diagram above, the dashed line from "inventory" marks a yet unresolved
way of specifying resources in the inventory (see #26).
OpenAPI spec generation
We generate an OpenAPI spec from comments in the source code. Every commit that
changes the API must update the relevant documentation.
To update the OpenAPI spec, you need to install swag:
go install github.com/swaggo/swag/cmd/swag@latest
To generate clients from the spec, you need to install
swagger in your system.
To do both steps at once:
make swag
⚠ - we still miss a good way to move/copy over the generated client to
the bitmask-core codebase. This should probably be automated somehow, with manual
overview.
Build
go build ./cmd/menshen
Run
Required parameters are --ca-file
, --client-cert-url
and an eip source (--from-eip-file
or --from-eip-url
). Use --verbose
to get debug output. You can start menshen from a v3 eip-service file:
./menshen --from-eip-file /tmp/eip.json --ca-file riseup-ca.pem --client-cert-url https://api.black.riseup.net:4430/3/cert
Alternatively you can start menshen with a eip-service.json from an URL:
./menshen --from-eip-url https://black.riseup.net:4430/3/config/eip-service.json --ca-file riseup-ca.pem --client-cert-url https://api.black.riseup.net:4430/3/cert
To visit the public url, you can point your browser to:
http://localhost:8443/api/swagger/index.html
If you want to make the general gateway and bridges endpoints public:
./menshen --from-eip-file /tmp/eip.json --allow-gateway-list --allow-bridge-list
If you're not running menshen
as part of an orchestration platform that can set up TLS certificates for you,
you can leverate the auto-tls
functionality (for instance, while running standalone nodes for development or quick testing):
./menshen --auto-tls --server-name example.com
For help on the optional flags, run with -h
:
❯ ./menshen -h
Usage of ./menshen:
--allow-bridge-list allow public bridge listing
--allow-gateway-list allow public gateway listing
--auto-tls configure auto TLS using Lets Encrypt
--ca-file string filename with CA certificate used for validating certificates
--client-cert-url string url that returns a valid OpenVPN certificate and private key in plain text
--from-eip-file string start from eip-service file (legacy)
--from-eip-url string start from eip-service url (legacy)
--lb-addr string Address for load balancer to listen on (default ":9003")
--localbridges string comma-separated list of addresses for the control port of bridges
--metrics-port int port for /metrics (prometheus) to listen on (default 9002)
--port int port to listen on (default 8443)
--server-name string server name (for LetsEncrypt AutoTLS)
--verbose set log verbosity to DEBUG
Config
You can either pass flags, as in the example above, or a yaml file, or environment variables.
The environment variables follow the uppercase-underscore convention and are prefixed with MENSHEN_
. So, to pass the equivalent of --port
, you'd pass MENSHEN_PORT
.
Other utilities
For convenience, there's a binary that can be used to get coordinates for the
locations of the remotes in your inventory with the same geolocation library
used by the API:
❯ go build ./cmd/locations
❯ ./locations /tmp/eip.json get-location
New York 40.71 -74.01
Paris 48.85 2.35
Seattle 47.61 -122.33
Amsterdam 52.37 4.90
Miami 25.77 -80.19
Montreal 45.52 -73.65
Bucket token auth
Resources (bridges and gateways) can be given a "bucket" property to denote that they should be restricted/not part of publicly available assets.
Admins can then generate auth tokens which would give end users access to those resources.
You can use the accompanying CLI to generate said tokens:
❯ go run ./cmd/tokens --buckets "bucket1,bucket2" --number-tokens 10
Tokens:
solitech_z6tV8f+1jpYMBgmE0J6jZQ==
solitech_bYnFp+YzPTp/71/edSDEiw==
solitech_pusRycrUBH9lxvkVcbIyXQ==
solitech_e9JckBd9QzYmSE4wo2jQBQ==
solitech_564x5U+rANCS1jbpvIeQvA==
solitech_zNcbJeFyMANj0kIxGruIpw==
solitech_t3/B7mdKB2tPbcnNdIejpw==
solitech_tLdCZT0QVPyPuNJFdlpvvQ==
solitech_G5ACBRpwqcivbMEkC708OA==
solitech_u6Zoe3ftUcVmLb3lm/KsSw==
These tokens can then be passed in as a x-menshen-auth-token
header when making requests to menshen which will allow that request access to private resources in "bucket1" and "bucket2".