Page MenuHomePhabricator

D15795.id.diff
No OneTemporary

D15795.id.diff

diff --git a/src/applications/almanac/management/AlmanacManagementRegisterWorkflow.php b/src/applications/almanac/management/AlmanacManagementRegisterWorkflow.php
--- a/src/applications/almanac/management/AlmanacManagementRegisterWorkflow.php
+++ b/src/applications/almanac/management/AlmanacManagementRegisterWorkflow.php
@@ -20,13 +20,6 @@
'help' => pht('Path to a private key for the host.'),
),
array(
- 'name' => 'allow-key-reuse',
- 'help' => pht(
- 'Register even if another host is already registered with this '.
- 'keypair. This is an advanced featuer which allows a pool of '.
- 'devices to share credentials.'),
- ),
- array(
'name' => 'identify-as',
'param' => 'name',
'help' => pht(
@@ -36,13 +29,13 @@
array(
'name' => 'force',
'help' => pht(
- 'Register this host even if keys already exist.'),
+ 'Register this host even if keys already exist on disk.'),
),
));
}
public function execute(PhutilArgumentParser $args) {
- $console = PhutilConsole::getConsole();
+ $viewer = $this->getViewer();
$device_name = $args->getArg('device');
if (!strlen($device_name)) {
@@ -51,7 +44,7 @@
}
$device = id(new AlmanacDeviceQuery())
- ->setViewer($this->getViewer())
+ ->setViewer($viewer)
->withNames(array($device_name))
->executeOne();
if (!$device) {
@@ -59,6 +52,23 @@
pht('No such device "%s" exists!', $device_name));
}
+ $identify_as = $args->getArg('identify-as');
+
+ $raw_device = $device_name;
+ if (strlen($identify_as)) {
+ $raw_device = $identify_as;
+ }
+
+ $identity_device = id(new AlmanacDeviceQuery())
+ ->setViewer($viewer)
+ ->withNames(array($raw_device))
+ ->executeOne();
+ if (!$identity_device) {
+ throw new PhutilArgumentUsageException(
+ pht(
+ 'No such device "%s" exists!', $raw_device));
+ }
+
$private_key_path = $args->getArg('private-key');
if (!strlen($private_key_path)) {
throw new PhutilArgumentUsageException(
@@ -67,7 +77,7 @@
if (!Filesystem::pathExists($private_key_path)) {
throw new PhutilArgumentUsageException(
- pht('Private key "%s" does not exist!', $private_key_path));
+ pht('No private key exists at path "%s"!', $private_key_path));
}
$raw_private_key = Filesystem::readFile($private_key_path);
@@ -85,8 +95,8 @@
if ($err) {
throw new PhutilArgumentUsageException(
pht(
- 'Unable to change ownership of a file to daemon user "%s". Run '.
- 'this command as %s or root.',
+ 'Unable to change ownership of an identity file to daemon user '.
+ '"%s". Run this command as %s or root.',
$phd_user,
$phd_user));
}
@@ -133,43 +143,39 @@
->withKeys(array($key_object))
->executeOne();
- if ($public_key) {
- if ($public_key->getObjectPHID() !== $device->getPHID()) {
- throw new PhutilArgumentUsageException(
- pht(
- 'The public key corresponding to the given private key is '.
- 'already associated with an object other than the specified '.
- 'device. You can not use a single private key to identify '.
- 'multiple devices or users.'));
- } else if (!$public_key->getIsTrusted()) {
- throw new PhutilArgumentUsageException(
- pht(
- 'The public key corresponding to the given private key is '.
- 'already associated with the device, but is not trusted. '.
- 'Registering this key would trust the other entities which '.
- 'hold it. Use a unique key, or explicitly enable trust for the '.
- 'current key.'));
- } else if (!$args->getArg('allow-key-reuse')) {
- throw new PhutilArgumentUsageException(
- pht(
- 'The public key corresponding to the given private key is '.
- 'already associated with the device. If you do not want to '.
- 'use a unique key, use --allow-key-reuse to permit '.
- 'reassociation.'));
- }
- } else {
- $public_key = id(new PhabricatorAuthSSHKey())
- ->setObjectPHID($device->getPHID())
- ->attachObject($device)
- ->setName($device->getSSHKeyDefaultName())
- ->setKeyType($key_object->getType())
- ->setKeyBody($key_object->getBody())
- ->setKeyComment(pht('Registered'))
- ->setIsTrusted(1);
+ if (!$public_key) {
+ throw new PhutilArgumentUsageException(
+ pht(
+ 'The public key corresponding to the given private key is not '.
+ 'yet known to Phabricator. Associate the public key with an '.
+ 'Almanac device in the web interface before registering hosts '.
+ 'with it.'));
+ }
+
+ if ($public_key->getObjectPHID() !== $device->getPHID()) {
+ $public_phid = $public_key->getObjectPHID();
+ $public_handles = $viewer->loadHandles(array($public_phid));
+ $public_handle = $public_handles[$public_phid];
+
+ throw new PhutilArgumentUsageException(
+ pht(
+ 'The public key corresponding to the given private key is already '.
+ 'associated with an object ("%s") other than the specified '.
+ 'device ("%s"). You can not use a single private key to identify '.
+ 'multiple devices or users.',
+ $public_handle->getFullName(),
+ $device->getName()));
}
+ if (!$public_key->getIsTrusted()) {
+ throw new PhutilArgumentUsageException(
+ pht(
+ 'The public key corresponding to the given private key is '.
+ 'properly associated with the device, but is not yet trusted. '.
+ 'Trust this key before registering devices with it.'));
+ }
- $console->writeOut(
+ echo tsprintf(
"%s\n",
pht('Installing public key...'));
@@ -179,18 +185,12 @@
Filesystem::writeFile($tmp_public, $raw_public_key);
execx('mv -f %s %s', $tmp_public, $stored_public_path);
- $console->writeOut(
+ echo tsprintf(
"%s\n",
pht('Installing private key...'));
execx('mv -f %s %s', $tmp_private, $stored_private_path);
- $raw_device = $device_name;
- $identify_as = $args->getArg('identify-as');
- if (strlen($identify_as)) {
- $raw_device = $identify_as;
- }
-
- $console->writeOut(
+ echo tsprintf(
"%s\n",
pht('Installing device %s...', $raw_device));
@@ -202,14 +202,7 @@
Filesystem::writeFile($tmp_device, $raw_device);
execx('mv -f %s %s', $tmp_device, $stored_device_path);
- if (!$public_key->getID()) {
- $console->writeOut(
- "%s\n",
- pht('Registering device key...'));
- $public_key->save();
- }
-
- $console->writeOut(
+ echo tsprintf(
"**<bg:green> %s </bg>** %s\n",
pht('HOST REGISTERED'),
pht(
diff --git a/src/docs/user/cluster/cluster_devices.diviner b/src/docs/user/cluster/cluster_devices.diviner
new file mode 100644
--- /dev/null
+++ b/src/docs/user/cluster/cluster_devices.diviner
@@ -0,0 +1,242 @@
+@title Cluster: Devices
+@group cluster
+
+Guide to configuring hosts to act as cluster devices.
+
+Cluster Context
+===============
+
+This document describes a step in configuring Phabricator to run on
+multiple hosts in a cluster configuration. This is an advanced feature. For
+more information on clustering, see @{article:Clustering Introduction}.
+
+In this context, device configuration is mostly relevant to configuring
+repository services in a cluster. You can find more details about this in
+@{article:Cluster: Repositories}.
+
+
+Overview
+========
+
+Some cluster services need to be able to authenticate themselves and interact
+with other services. For example, two repository hosts holding copies of the
+same repository must be able to fetch changes from one another, even if the
+repository is private.
+
+Within a cluster, devices authenticate using SSH keys. Some operations happen
+over SSH (using keys in a normal way, as you would when running `ssh` from the
+command line), while others happen over HTTP (using SSH keys to sign requests).
+
+Before hosts can authenticate to one another, you need to configure the
+credentials so other devices know the keys can be trusted. Beyond establishing
+trust, this configuration will establish //device identity//, so each host
+knows which device it is explicitly.
+
+Today, this is primarily necessary when configuring repository clusters.
+
+
+Using Almanac
+=============
+
+The tool Phabricator uses to manage cluster devices is the **Almanac**
+application, and most configuration will occur through the application's web
+UI. If you are not familiar with it, see @{article:Almanac User Guide} first.
+This document assumes you are familiar with Almanac concepts.
+
+
+What Lies Ahead
+===============
+
+Here's a brief overview of the steps required to register cluster devices. The
+remainder of this document walks through these points in more detail.
+
+ - Create an Almanac device record for each device.
+ - Generate, add, and trust SSH keys if necessary.
+ - Install Phabricator on the host.
+ - Use `bin/almanac register` from the host to register it as a device.
+
+See below for guidance on each of these steps.
+
+
+Individual vs Shared Keys
+=========================
+
+Before getting started, you should choose how you plan to manage device SSH
+keys. Trust and device identity are handled separately, and there are two ways
+to set up SSH keys so that devices can authenticate with one another:
+
+ - you can generate a unique SSH key for each device; or
+ - you can generate one SSH key and share it across multiple devices.
+
+Using **unique keys** allows the tools to do some more sanity/safety checks and
+makes it a bit more difficult to misconfigure things, but you'll have to do
+more work managing the actual keys. This may be a better choice if you are
+setting up a small cluster (2-3 devices) for the first time.
+
+Using **shared keys** makes key management easier but safety checks won't be
+able to catch a few kinds of mistakes. This may be a better choice if you are
+setting up a larger cluster, plan to expand the cluster later, or have
+experience with Phabricator clustering.
+
+Because all cluster keys are all-powerful, there is no material difference
+between these methods from a security or trust viewpoint. Unique keys are just
+potentially easier to administrate at small scales, while shared keys are
+easier at larger scales.
+
+
+Create Almanac Device Records
+=============================
+
+For each host you plan to make part of a Phabricator cluster, go to the
+{nav Almanac} application and create a **device** record. For guidance on this
+application, see @{article:Almanac User Guide}.
+
+Add **interfaces** to each device record so Phabricator can tell how to
+connect to these hosts. Normally, you'll add one HTTP interface (usually on
+port 80) and one SSH interface (often on port 22) to each device:
+
+For example, if you are building a two-host repository cluster, you may end
+up with records that look like these:
+
+ - Device: `repo001.mycompany.net`
+ - Interface: `123.0.0.1:22`
+ - Interface: `123.0.0.1:80`
+ - Device: `repo002.mycopmany.net`
+ - Interface: `123.0.0.2:22`
+ - Interface: `123.0.0.2:80`
+
+Note that these hosts will normally run two `sshd` ports: the standard `sshd`
+which you connect to to operate and administrate the host, and the special
+Phabricator `sshd` that you connect to to clone and push repositories.
+
+You should specify the Phabricator `sshd` port, **not** the standard `sshd`
+port.
+
+If you're using **unique** SSH keys for each device, continue to the next step.
+
+If you're using **shared** SSH keys, create a third device with no interfaces,
+like `keywarden.mycompany.net`. This device will just be used as a container to
+hold the trusted SSH key and is not a real device.
+
+NOTE: Do **not** create a **service** record yet. Today, service records become
+active immediately once they are created, and you haven't set things up yet.
+
+
+Generate and Trust SSH Keys
+===========================
+
+Next, you need to generate or upload SSH keys and mark them as trusted. Marking
+a key as trusted gives it tremendous power.
+
+If you're using **unique** SSH keys, upload or generate a key for each
+individual device from the device detail screen in the Almanac web UI. Save the
+private keys for the next step.
+
+If you're using a **shared** SSH key, upload or generate a single key for
+the keywarden device from the device detail screen in the Almanac web UI.
+Save the private key for the next step.
+
+Regardless of how many keys you generated, take the key IDs from the tables
+in the web UI and run this command from the command line for each key, to mark
+each key as trusted:
+
+```
+phabricator/ $ ./bin/almanac trust-key --id <key-id-1>
+phabricator/ $ ./bin/almanac trust-key --id <key-id-2>
+...
+```
+
+The warnings this command emits are serious. The private keys are now trusted,
+and allow any user or device possessing them to sign requests that bypass
+policy checks without requiring additional credentials. Guard them carefully!
+
+If you need to revoke trust for a key later, use `untrust-key`:
+
+```
+phabricator/ $ ./bin/almanac untrust-key --id <key-id>
+```
+
+Once the keys are trusted, continue to the next step.
+
+
+Install Phabricator
+===================
+
+If you haven't already, install Phabricator on each device you plan to enroll
+in the cluster. Cluster repository devices must provide services over both HTTP
+and SSH, so you need to install and configure both a webserver and a
+Phabricator `sshd` on these hosts.
+
+Generally, you will follow whatever process you otherwise use when installing
+Phabricator.
+
+NOTE: Do not start the daemons on the new devices yet. They won't work properly
+until you've finished configuring things.
+
+Once Phabricator is installed, you can enroll the devices in the cluster by
+registering them.
+
+
+Register Devices
+================
+
+To register a host as an Almanac device, use `bin/almanac register`.
+
+If you are using **unique** keys, run it like this:
+
+```
+$ ./bin/almanac register \
+ --device <device> \
+ --private-key <key>
+```
+
+For example, you might run this command on `repo001` when using unique keys:
+
+```
+$ ./bin/almanac register \
+ --device repo001.mycompany.net \
+ --private-key /path/to/private.key
+```
+
+If you are using a **shared** key, this will be a little more complicated
+because you need to override some checks that are intended to prevent mistakes.
+Use the `--identify-as` flag to choose a device identity:
+
+```
+$ ./bin/almanac register \
+ --device <keywarden-device> \
+ --private-key <key> \
+ --identify-as <actual-device>
+```
+
+For example, you might run this command on `repo001` when using a shared key:
+
+```
+$ ./bin/almanac register
+ --device keywarden.mycompany.net \
+ --private-key /path/to/private-key \
+ --identify-as repo001.mycompany.net
+```
+
+In particular, note that `--device` is always the **trusted** device associated
+with the trusted key. The `--identify-as` flag allows several different hosts
+to share the same key but still identify as different devices.
+
+The overall effect of the `bin/almanac` command is to copy identity and key
+files into `phabricator/conf/keys/`. You can inspect the results by examining
+that directory. The helper script just catches potential mistakes and makes
+sure the process is completed correctly.
+
+Note that a copy of the active private key is stored in the `conf/keys/`
+directory permanently.
+
+
+Next Steps
+==========
+
+Now that devices are registered, you can build cluster services from them.
+Return to the relevant cluster service documentation to continue:
+
+ - build repository clusters with @{article:Cluster: Repositories};
+ - return to @{article:Clustering Introduction}; or
+ - review the Almanac application with @{article:Almanac User Guide}.

File Metadata

Mime Type
text/plain
Expires
Wed, Oct 23, 5:00 PM (3 w, 5 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6737243
Default Alt Text
D15795.id.diff (15 KB)

Event Timeline