Signal agent token is required
The agent needs to be able to understand if the agent token is supported and is a mandatory feature of the ironic deployment as that can alter some of the behavior of the agent itself. Also adds documentation on the subject for administrators. Story: 2007025 Task: 37821 Change-Id: Ic635e0ed6d378d6a34a4a82e66ca647eee33bc26
This commit is contained in:
parent
392f2a56bf
commit
deca07de3c
@ -479,6 +479,9 @@ IRONIC_DEPLOY_LOGS_LOCAL_PATH=${IRONIC_DEPLOY_LOGS_LOCAL_PATH:-$IRONIC_VM_LOG_DI
|
||||
# Fast track option
|
||||
IRONIC_DEPLOY_FAST_TRACK=${IRONIC_DEPLOY_FAST_TRACK:-False}
|
||||
|
||||
# Agent Token requirement
|
||||
IRONIC_REQUIRE_AGENT_TOKEN=${IRONIC_REQUIRE_AGENT_TOKEN:-True}
|
||||
|
||||
# Define baremetal min_microversion in tempest config. Default value None is picked from tempest.
|
||||
TEMPEST_BAREMETAL_MIN_MICROVERSION=${TEMPEST_BAREMETAL_MIN_MICROVERSION:-}
|
||||
|
||||
@ -1294,6 +1297,8 @@ function configure_ironic {
|
||||
# Set fast track options
|
||||
iniset $IRONIC_CONF_FILE deploy fast_track $IRONIC_DEPLOY_FAST_TRACK
|
||||
|
||||
# Set requirement for agent tokens
|
||||
iniset $IRONIC_CONF_FILE DEFAULT require_agent_token $IRONIC_REQUIRE_AGENT_TOKEN
|
||||
# No need to check if RabbitMQ is enabled, this call does it in a smart way
|
||||
if [[ "$IRONIC_RPC_TRANSPORT" == "oslo" ]]; then
|
||||
iniset_rpc_backend ironic $IRONIC_CONF_FILE
|
||||
|
121
doc/source/admin/agent-token.rst
Normal file
121
doc/source/admin/agent-token.rst
Normal file
@ -0,0 +1,121 @@
|
||||
.. _agent_token:
|
||||
|
||||
===========
|
||||
Agent Token
|
||||
===========
|
||||
|
||||
Purpose
|
||||
=======
|
||||
|
||||
The concept of agent tokens is to provide a mechanism by which the
|
||||
relationship between an operating deployment of the Bare Metal Service
|
||||
and an instance of the ``ironic-python-agent`` is verified. In a sense,
|
||||
this token can be viewed as a session identifier or authentication token.
|
||||
|
||||
.. warning::
|
||||
This functionality does not remove the risk of a man-in-the-middle attack
|
||||
that could occur from connection intercept or when TLS is not used for
|
||||
all communication.
|
||||
|
||||
This becomes useful in the case of deploying an "edge" node where intermediate
|
||||
networks are not trustworthy.
|
||||
|
||||
How it works
|
||||
============
|
||||
|
||||
These tokens are provided in one of two ways to the running agent.
|
||||
|
||||
1. A pre-generated token which is embedded into virtual media ISOs.
|
||||
2. A one-time generated token that are provided upon the first "lookup"
|
||||
of the node.
|
||||
|
||||
In both cases, the tokens are a randomly generated length of 128 characters.
|
||||
|
||||
Once the token has been provided, the token cannot be retrieved or accessed.
|
||||
It remains available to the conductors, and is stored in memory of the
|
||||
``ironic-python-agent``.
|
||||
|
||||
.. note::
|
||||
In the case of the token being embedded with virtual media, it is read
|
||||
from a configuration file with-in the image. Ideally this should be paired
|
||||
with Swift temporary URLs.
|
||||
|
||||
With the token is available in memory in the agent, the token is embedded with
|
||||
``heartbeat`` operations to the ironic API endpoint. This enables the API to
|
||||
authenticate the heartbeat request, and refuse "heartbeat" requests from the
|
||||
``ironic-python-agent``. With the ``Ussuri`` release, the confiuration option
|
||||
``[DEFAULT]require_agent_token`` can be set ``True`` to explicitly require
|
||||
token use.
|
||||
|
||||
.. warning::
|
||||
If the Bare Metal Service is updated, and the version of
|
||||
``ironic-python-agent`` should be updated to enable this feature.
|
||||
|
||||
In addition to heartbeats being verified, commands from the
|
||||
``ironic-conductor`` service to the ``ironic-python-agent`` also include the
|
||||
token, allowing the agent to authenticate the caller.
|
||||
|
||||
|
||||
With Virtual Media
|
||||
------------------
|
||||
|
||||
.. seqdiag::
|
||||
:scale: 80
|
||||
|
||||
diagram {
|
||||
API; Conductor; Baremetal; Swift; IPA;
|
||||
activation = none;
|
||||
span_height = 1;
|
||||
edge_length = 250;
|
||||
default_note_color = white;
|
||||
default_fontsize = 14;
|
||||
|
||||
Conductor -> Conductor [label = "Generates a random token"];
|
||||
Conductor -> Conductor [label = "Generates configuration for IPA ramdisk"];
|
||||
Conductor -> Swift [label = "IPA image, with configuration is uploaded"];
|
||||
Conductor -> Baremetal [label = "Attach IPA virtual media in Swift as virtual CD"];
|
||||
Conductor -> Baremetal [label = "Conductor turns power on"];
|
||||
Baremetal -> Swift [label = "Baremetal reads virtual media"];
|
||||
Baremetal -> Baremetal [label = "Boots IPA virtual media image"];
|
||||
Baremetal -> Baremetal [label = "IPA is started"];
|
||||
IPA -> Baremetal [label = "IPA loads configuration and agent token into memory"];
|
||||
IPA -> API [label = "Lookup node"];
|
||||
API -> IPA [label = "API responds with node UUID and token value of '******'"];
|
||||
IPA -> API [label = "Heartbeat with agent token"];
|
||||
}
|
||||
|
||||
With PXE/iPXE/etc.
|
||||
------------------
|
||||
|
||||
.. seqdiag::
|
||||
:scale: 80
|
||||
|
||||
diagram {
|
||||
API; Conductor; Baremetal; iPXE; IPA;
|
||||
activation = none;
|
||||
span_height = 1;
|
||||
edge_length = 250;
|
||||
default_note_color = white;
|
||||
default_fontsize = 14;
|
||||
|
||||
Conductor -> Baremetal [label = "Conductor turns power on"];
|
||||
Baremetal -> iPXE [label = "Baremetal reads kernel/ramdisk and starts boot"];
|
||||
Baremetal -> Baremetal [label = "Boots IPA virtual media image"];
|
||||
Baremetal -> Baremetal [label = "IPA is started"];
|
||||
IPA -> Baremetal [label = "IPA loads configuration"];
|
||||
IPA -> API [label = "Lookup node"];
|
||||
API -> Conductor [label = "API requests conductor to generates a random token"];
|
||||
API -> IPA [label = "API responds with node UUID and token value"];
|
||||
IPA -> API [label = "Heartbeat with agent token"];
|
||||
}
|
||||
|
||||
Agent Configuration
|
||||
===================
|
||||
|
||||
An additional setting which may be leveraged with the ``ironic-python-agent``
|
||||
is a ``agent_token_required`` setting. Under normal circumstances, this
|
||||
setting can be asserted via the configuration supplied from the Bare Metal
|
||||
service deployment upon the ``lookup`` action, but can be asserted via the
|
||||
embedded configuration for the agent in the ramdisk. This setting is also
|
||||
available via kernel command line as ``ipa-agent-token-required``.
|
||||
|
@ -32,6 +32,7 @@ the services.
|
||||
Windows Images <building-windows-images>
|
||||
Troubleshooting FAQ <troubleshooting>
|
||||
Power Sync with the Compute Service <power-sync>
|
||||
Agent Token <agent-token>
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
|
@ -53,7 +53,10 @@ def config(token):
|
||||
'statsd_port': CONF.metrics_statsd.agent_statsd_port
|
||||
},
|
||||
'heartbeat_timeout': CONF.api.ramdisk_heartbeat_timeout,
|
||||
'agent_token': token
|
||||
'agent_token': token,
|
||||
# Not an API version based indicator, passing as configuration
|
||||
# as the signifigants indicates support should also be present.
|
||||
'agent_token_required': CONF.require_agent_token,
|
||||
}
|
||||
|
||||
|
||||
|
@ -62,7 +62,7 @@ class TestLookup(test_api_base.BaseApiTest):
|
||||
self.mock_get_node_with_token.return_value = node
|
||||
|
||||
def _check_config(self, data):
|
||||
expected_metrics = {
|
||||
expected_config = {
|
||||
'metrics': {
|
||||
'backend': 'statsd',
|
||||
'prepend_host': CONF.metrics.agent_prepend_host,
|
||||
@ -76,9 +76,10 @@ class TestLookup(test_api_base.BaseApiTest):
|
||||
'statsd_port': CONF.metrics_statsd.agent_statsd_port
|
||||
},
|
||||
'heartbeat_timeout': CONF.api.ramdisk_heartbeat_timeout,
|
||||
'agent_token': mock.ANY
|
||||
'agent_token': mock.ANY,
|
||||
'agent_token_required': False,
|
||||
}
|
||||
self.assertEqual(expected_metrics, data['config'])
|
||||
self.assertEqual(expected_config, data['config'])
|
||||
self.assertIsNotNone(data['config']['agent_token'])
|
||||
self.assertNotEqual('******', data['config']['agent_token'])
|
||||
|
||||
|
@ -151,6 +151,8 @@
|
||||
|
||||
export DEVSTACK_LOCAL_CONFIG+=$'\n'"IRONIC_VM_COUNT=7"
|
||||
|
||||
export DEVSTACK_LOCAL_CONFIG+=$'\n'"IRONIC_REQUIRE_AGENT_TOKEN=False"
|
||||
|
||||
# Ensure the ironic-vars-EARLY file exists
|
||||
touch ironic-vars-early
|
||||
# Pull in the EARLY variables injected by the optional builders
|
||||
|
@ -97,6 +97,8 @@
|
||||
|
||||
export DEVSTACK_LOCAL_CONFIG+=$'\n'"IRONIC_VM_COUNT=7"
|
||||
|
||||
export DEVSTACK_LOCAL_CONFIG+=$'\n'"IRONIC_REQUIRE_AGENT_TOKEN=False"
|
||||
|
||||
# Ensure the ironic-vars-EARLY file exists
|
||||
touch ironic-vars-early
|
||||
# Pull in the EARLY variables injected by the optional builders
|
||||
|
19
releasenotes/notes/agent-token-support-0a5b5aa1585dfbb5.yaml
Normal file
19
releasenotes/notes/agent-token-support-0a5b5aa1585dfbb5.yaml
Normal file
@ -0,0 +1,19 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Adds support of ``agent token`` which serves as a mechanism to secure
|
||||
the normally unauthenticated API endpoints in ironic which are used in
|
||||
the mechanics of baremetal provisioning. This feature is optional, however
|
||||
operators may require this feature by changing the
|
||||
``[DEFAULT]require_agent_token`` setting to ``True``.
|
||||
upgrades:
|
||||
- |
|
||||
In order to use the new Agent Token support, all ramdisk settings should
|
||||
be updated for all nodes in ironic. If token use is required by ironic's
|
||||
configuration, and the ramdisks have not been updated, then all
|
||||
deployment, cleaning, and rescue operations will fail until the version of
|
||||
the ironic-python-agent ramdisk has been updated.
|
||||
issues:
|
||||
- |
|
||||
The ``ansible`` deployment interface does not support use of an
|
||||
``agent token`` at this time.
|
Loading…
Reference in New Issue
Block a user