Add cluster.addresses and require membership before accepting cluster authentication tokens
Summary:
Ref T2783. Ref T6706.
- Add `cluster.addresses`. This is a whitelist of CIDR blocks which define cluster hosts.
- When we recieve a request that has a cluster-based authentication token, require the cluster to be configured and require the remote address to be a cluster member before we accept it.
- This provides a general layer of security for these mechanisms.
- In particular, it means they do not work by default on unconfigured hosts.
- When cluster addresses are configured, and we receive a request //to// an address not on the list, reject it.
- This provides a general layer of security for getting the Ops side of cluster configuration correct.
- If cluster nodes have public IPs and are listening on them, we'll reject requests.
- Basically, this means that any requests which bypass the LB get rejected.
Test Plan:
- With addresses not configured, tried to make requests; rejected for using a cluster auth mechanism.
- With addresses configred wrong, tried to make requests; rejected for sending from (or to) an address outside of the cluster.
- With addresses configured correctly, made valid requests.
Reviewers: btrahan
Reviewed By: btrahan
Subscribers: epriestley
Maniphest Tasks: T6706, T2783
Differential Revision: https://secure.phabricator.com/D11159
This commit is contained in:
@@ -275,6 +275,50 @@ abstract class AphrontApplicationConfiguration {
|
||||
final public function buildController() {
|
||||
$request = $this->getRequest();
|
||||
|
||||
// If we're configured to operate in cluster mode, reject requests which
|
||||
// were not received on a cluster interface.
|
||||
//
|
||||
// For example, a host may have an internal address like "170.0.0.1", and
|
||||
// also have a public address like "51.23.95.16". Assuming the cluster
|
||||
// is configured on a range like "170.0.0.0/16", we want to reject the
|
||||
// requests received on the public interface.
|
||||
//
|
||||
// Ideally, nodes in a cluster should only be listening on internal
|
||||
// interfaces, but they may be configured in such a way that they also
|
||||
// listen on external interfaces, since this is easy to forget about or
|
||||
// get wrong. As a broad security measure, reject requests received on any
|
||||
// interfaces which aren't on the whitelist.
|
||||
|
||||
$cluster_addresses = PhabricatorEnv::getEnvConfig('cluster.addresses');
|
||||
if ($cluster_addresses) {
|
||||
$server_addr = idx($_SERVER, 'SERVER_ADDR');
|
||||
if (!$server_addr) {
|
||||
if (php_sapi_name() == 'cli') {
|
||||
// This is a command line script (probably something like a unit
|
||||
// test) so it's fine that we don't have SERVER_ADDR defined.
|
||||
} else {
|
||||
throw new AphrontUsageException(
|
||||
pht('No SERVER_ADDR'),
|
||||
pht(
|
||||
'Phabricator is configured to operate in cluster mode, but '.
|
||||
'SERVER_ADDR is not defined in the request context. Your '.
|
||||
'webserver configuration needs to forward SERVER_ADDR to '.
|
||||
'PHP so Phabricator can reject requests received on '.
|
||||
'external interfaces.'));
|
||||
}
|
||||
} else {
|
||||
if (!PhabricatorEnv::isClusterAddress($server_addr)) {
|
||||
throw new AphrontUsageException(
|
||||
pht('External Interface'),
|
||||
pht(
|
||||
'Phabricator is configured in cluster mode and the address '.
|
||||
'this request was received on ("%s") is not whitelisted as '.
|
||||
'a cluster address.',
|
||||
$server_addr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (PhabricatorEnv::getEnvConfig('security.require-https')) {
|
||||
if (!$request->isHTTPS()) {
|
||||
$https_uri = $request->getRequestURI();
|
||||
|
||||
Reference in New Issue
Block a user