Cryptography and Message Signing¶
fedmsg.crypto - Cryptographic component of fedmsg.
In general, we assume that ‘everything on the bus is public’. Even though all
the zmq endpoints are firewalled off from the outside world with iptables, we
do have a forwarding service setup that indiscriminantly
forwards all messages to anyone who wants them.
fedmsg.commands.gateway.gateway for that service.)
So, the issue is not encrypting messages so they can’t be read. It is up to
sensitive services like FAS to not send sensitive information in the first
place (like passwords, for instance).
However, since at some point, services will respond to and act on messages that come across the bus, we need facilities for guaranteeing a message comes from where it ought to come from. (Tangentially, message consumers need a simple way to declare where they expect their messages to come from and have the filtering and validation handled for them).
There should also be a convenient way to turn crypto off both globally and locally. Justification: a developer may want to work out a bug without any messages being signed or validated. In production, certain senders may send non-critical data from a corner of Fedora Infrastructure in which it’s difficult to sign messages. A consumer of those messages should be allowed to ignore validation for those and only those expected unsigned messages
Two backend methods are available to accomplish this:
Which backend is used is configured by the crypto_backend configuration value.
To accomplish message signing, fedmsg must be able to read certificates and a
private key on disk in the case of the
or to read public and private GnuPG keys in the came of the
fedmsg.crypto.gpg backend. For message validation, it only need be
able to read the x509 certificate or gpg public key. Exactly which
certificates are used are determined by looking up the
certname in the
certnames config dict.
We use a large number of certs for the deployment of fedmsg. We have one cert per service-host. For example, if we have 3 fedmsg-enabled services and each service runs on 10 hosts, then we have 30 unique certificate/key pairs in all.
The intent is to create difficulty for attackers. If a low-security service on a particular box is compromised, we don’t want the attacker automatically have access to the same certificate used for signing high-security service messages.
Furthermore, attempts are made at the sysadmin-level to ensure that fedmsg-enabled services run as users that have exclusive read access to their own keys. See the Fedora Infrastructure SOP for more information (including how to generate new certs/bring up new services).
Messages are also checked to see if the name of the certificate they bear and the topic they’re routed on match up in a routing_policy dict. Is the build server allowed to send messages about wiki updates? Not if the routing policy has anything to say about it.
By analogy, “signature validation is to authentication as routing policy checks are to authorization.”
If the topic of a message appears in the routing_policy, the name borne on the certificate must also appear under the associated list of permitted publishers or the message is marked invalid.
If the topic of a message does not appear in the routing_policy, two different courses of action are possible:
Typically, you’ll deploy fedmsg with nitpicky mode turned off. You can build your policy over time as you determine what services will be sending what messages. Once deployment of fedmsg reaches a certain level of stability, you can turn nitpicky mode on for enhanced security, but by doing so you may break certain message paths that you’ve forgotten to include in your routing policy.
By convention, configuration values for
fedmsg.crypto are kept in
/etc/fedmsg.d/ssl.py, although technically they can be kept in any
/etc/fedmsg.d (or in any of the config locations checked
The cryptography routines expect the following values to be defined:
For general information on configuration, see
fedmsg.crypto encapsulates standalone functions for:
- Message signing.
- Signature validation.
- Stripping crypto information for view.
Initialize the crypto backend.
The backend can be one of two plugins:
- ‘x509’ - Uses x509 certificates.
- ‘gpg’ - Uses GnuPG keys.
Insert two new fields into the message dict and return it.
Those fields are:
- ‘signature’ - the computed message digest of the JSON repr.
- ‘certificate’ - the base64 certificate or gpg key of the signator.
Strip credentials from a message dict.
A new dict is returned without either signature or certificate keys. This method can be called safely; the original dict is not modified.
This function is applicable using either using the x509 or gpg backends.
Return true or false if the message is signed appropriately.
validate_signed_by(message, signer, **config)¶
Validate that a message was signed by a particular certificate.
This works much like
validate(...), but additionally accepts a
signerargument. It will reject a message for any of the regular circumstances, but will also reject it if its not signed by a cert with the argued name.