|
|
|
|
@ -27,6 +27,9 @@ uses standard PKI. TLS is configured by providing a valid certificate (and
|
|
|
|
|
optionally CA certificate or chain) and clients must trust that CA chain. This
|
|
|
|
|
provides broad compatibility with a wide array of clients.
|
|
|
|
|
|
|
|
|
|
It is possible to require client certificates; see the configuration for
|
|
|
|
|
`listener` blocks to see the available TLS parameters.
|
|
|
|
|
|
|
|
|
|
## Worker-to-Controller TLS
|
|
|
|
|
|
|
|
|
|
The service exposed by the a Controller to handle Worker requests takes
|
|
|
|
|
@ -39,36 +42,36 @@ parameters, which forms the entire allowable CA chain for the connection.
|
|
|
|
|
TLS establishment is performed as follows:
|
|
|
|
|
|
|
|
|
|
1. The Worker generates a TLS certificate acting as a self-contained chain, as
|
|
|
|
|
well as a nonce. The generated key type is currently Ed25519. The certificate is
|
|
|
|
|
valid for a total of 2.5 minutes: thirty seconds before the current time (to
|
|
|
|
|
allow for some minor clock drift) and two minutes after (to allow time to
|
|
|
|
|
establish the connection).
|
|
|
|
|
well as a nonce. The generated key type is currently Ed25519. The certificate is
|
|
|
|
|
valid for a total of 2.5 minutes: thirty seconds before the current time (to
|
|
|
|
|
allow for some minor clock drift) and two minutes after (to allow time to
|
|
|
|
|
establish the connection).
|
|
|
|
|
|
|
|
|
|
2. The Worker marshals the TLS chain and nonce and encrypts the resulting bytes
|
|
|
|
|
via the shared KMS. This value is marshaled and split into chunks.
|
|
|
|
|
via the shared KMS. This value is marshaled and split into chunks.
|
|
|
|
|
|
|
|
|
|
3. The Worker establishes a TLS 1.3 connection to the Controller. The encrypted
|
|
|
|
|
value is transmitted to the Controller via the TLS ALPN field as numbered
|
|
|
|
|
chunks.
|
|
|
|
|
value is transmitted to the Controller via the TLS ALPN field as numbered
|
|
|
|
|
chunks.
|
|
|
|
|
|
|
|
|
|
4. The Controller reads the chunks and reassembles them into the original
|
|
|
|
|
encrypted value.
|
|
|
|
|
encrypted value.
|
|
|
|
|
|
|
|
|
|
5. The Controller decrypts this value via the shared KMS. If successful, the
|
|
|
|
|
Controller validates that the nonce is not known, to ensure that this is not a
|
|
|
|
|
replay.
|
|
|
|
|
Controller validates that the nonce is not known, to ensure that this is not a
|
|
|
|
|
replay.
|
|
|
|
|
|
|
|
|
|
6. The Controller uses the decrypted parameters to configures its TLS stack with
|
|
|
|
|
the same certificate and key.
|
|
|
|
|
the same certificate and key.
|
|
|
|
|
|
|
|
|
|
7. The connection is mutually authenticated; on each end, only the single
|
|
|
|
|
self-signed CA certificate that was securely transmitted is configured as a
|
|
|
|
|
valid root CA for validation checking.
|
|
|
|
|
self-signed CA certificate that was securely transmitted is configured as a
|
|
|
|
|
valid root CA for validation checking.
|
|
|
|
|
|
|
|
|
|
8. If successful, the nonce is stored in the database along with an expiration
|
|
|
|
|
time set several minutes past the actual expiration time of the certificate
|
|
|
|
|
itself. This ensures that any replay attempt that occurs is detected and
|
|
|
|
|
rejected until after the certificate is otherwise invalid.
|
|
|
|
|
time set several minutes past the actual expiration time of the certificate
|
|
|
|
|
itself. This ensures that any replay attempt that occurs is detected and
|
|
|
|
|
rejected until after the certificate is otherwise invalid.
|
|
|
|
|
|
|
|
|
|
## Client-to-Worker TLS
|
|
|
|
|
|
|
|
|
|
@ -80,56 +83,56 @@ Here's how it works:
|
|
|
|
|
TLS establishment is performed as follows:
|
|
|
|
|
|
|
|
|
|
1. When the session is authorized, the Controller generates a TLS certificate
|
|
|
|
|
acting as a self-contained chain. This is similar to the Worker-to-Controller
|
|
|
|
|
flow above, but in this case the key is an Ed25519 key generated via derivation
|
|
|
|
|
from a base key within the Controller, which itself is protected at rest via the
|
|
|
|
|
controller's "root" KMS. The derivation uses HKDF-SHA256 with the user ID and
|
|
|
|
|
the session ID as inputs. The lifetime of the certificate is tied to the
|
|
|
|
|
lifetime of the session.
|
|
|
|
|
acting as a self-contained chain. This is similar to the Worker-to-Controller
|
|
|
|
|
flow above, but in this case the key is an Ed25519 key generated via derivation
|
|
|
|
|
from a base key within the Controller, which itself is protected at rest via the
|
|
|
|
|
controller's "root" KMS. The derivation uses HKDF-SHA256 with the user ID and
|
|
|
|
|
the session ID as inputs. The lifetime of the certificate is tied to the
|
|
|
|
|
lifetime of the session.
|
|
|
|
|
|
|
|
|
|
2. The certificate and private key (along with other session authorization data,
|
|
|
|
|
notably the session ID) are returned to the client as part of the output of an
|
|
|
|
|
`authorize-session` action against a target, in the form of a marshaled object.
|
|
|
|
|
The controller persists the certificate in the database, but not the private
|
|
|
|
|
key.
|
|
|
|
|
notably the session ID) are returned to the client as part of the output of an
|
|
|
|
|
`authorize-session` action against a target, in the form of a marshaled object.
|
|
|
|
|
The controller persists the certificate in the database, but not the private
|
|
|
|
|
key.
|
|
|
|
|
|
|
|
|
|
3. The client (that is, the `boundary connect` command) parses this session
|
|
|
|
|
authorization data and uses the certificate and private key to construct a TLS
|
|
|
|
|
stack. It then makes a TLS 1.3 connection to a Worker, passing the session ID as
|
|
|
|
|
the SNI value.
|
|
|
|
|
authorization data and uses the certificate and private key to construct a TLS
|
|
|
|
|
stack. It then makes a TLS 1.3 connection to a Worker, passing the session ID as
|
|
|
|
|
the SNI value.
|
|
|
|
|
|
|
|
|
|
4. The worker sees the SNI value and makes a call to the Controller to fetch
|
|
|
|
|
session authorization information, keyed by the session ID.
|
|
|
|
|
session authorization information, keyed by the session ID.
|
|
|
|
|
|
|
|
|
|
5. The Controller looks for a session with the given ID and fetches the
|
|
|
|
|
information. Using the session ID and the user ID tied to the session, it
|
|
|
|
|
re-derives the private key and passes all of the information back to the Worker.
|
|
|
|
|
Notably, this may include a TOFU (Trust On First Use) token.
|
|
|
|
|
information. Using the session ID and the user ID tied to the session, it
|
|
|
|
|
re-derives the private key and passes all of the information back to the Worker.
|
|
|
|
|
Notably, this may include a TOFU (Trust On First Use) token.
|
|
|
|
|
|
|
|
|
|
6. The Worker uses the given data to construct a TLS stack with the same
|
|
|
|
|
certificate and key.
|
|
|
|
|
certificate and key.
|
|
|
|
|
|
|
|
|
|
7. The connection is mutually authenticated; on each end, only the single
|
|
|
|
|
self-signed CA certificate that was securely transmitted is configured as a
|
|
|
|
|
valid root CA for validation checking.
|
|
|
|
|
self-signed CA certificate that was securely transmitted is configured as a
|
|
|
|
|
valid root CA for validation checking.
|
|
|
|
|
|
|
|
|
|
8. If successful, the client and Worker perform a handshake, where the client
|
|
|
|
|
passes a TOFU (Trust On First Use) value to the Worker. This value is derived
|
|
|
|
|
when the client is created; that is, when `boundary connect` is run. This allows
|
|
|
|
|
for a single client to make multiple connections within a session, without the
|
|
|
|
|
credentials being usable via a different client:
|
|
|
|
|
passes a TOFU (Trust On First Use) value to the Worker. This value is derived
|
|
|
|
|
when the client is created; that is, when `boundary connect` is run. This allows
|
|
|
|
|
for a single client to make multiple connections within a session, without the
|
|
|
|
|
credentials being usable via a different client:
|
|
|
|
|
|
|
|
|
|
* If the worker was not given a TOFU token in step 5, the worker submits the
|
|
|
|
|
- If the worker was not given a TOFU token in step 5, the worker submits the
|
|
|
|
|
value to the Controller. The Controller verifies (via a database transaction)
|
|
|
|
|
that the session has not had a different TOFU token submitted prior and stores
|
|
|
|
|
it. Otherwise it's rejected, and so is the connection, as a possible replay
|
|
|
|
|
attack.
|
|
|
|
|
|
|
|
|
|
* If the Worker was given a TOFU token in step 5, it checks to see whether the
|
|
|
|
|
|
|
|
|
|
- If the Worker was given a TOFU token in step 5, it checks to see whether the
|
|
|
|
|
token values match. If not, the connection is rejected as a possible replay
|
|
|
|
|
attack.
|
|
|
|
|
|
|
|
|
|
In the future, to support other client paradigms, we may support user
|
|
|
|
|
configuration of the Worker's client-facing TLS. In this model, the shared
|
|
|
|
|
certificate/private key would instead act as credentials for the session,
|
|
|
|
|
similar to a username/password.
|
|
|
|
|
similar to a username/password.
|
|
|
|
|
|