Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tunnel sled initialization requests through sprockets sessions #1128

Merged
merged 4 commits into from
Jun 6, 2022

Conversation

jgallagher
Copy link
Contributor

@jgallagher jgallagher commented May 27, 2022

Changes included in this PR:

  • The sled-agent binary will look for a config-sp.toml file (similarly to how it looks for config-rss.toml) that defines the configuration for a simulated SP/RoT. If found, it will tweak the bootstrap config to set up a sprockets proxy (more on this below).
  • The bootstrap-agent server will attempt to "detect" an SP. Currently the only mechanism implemented here is that if the config for a simulated SP is present, it will spawn a simulated SP / RoT pair and return a handle to it.
  • If we have a handle to an SP, we will start a sprockets server-side proxy that sits in front of the bootstrap-agent dropshot server.
  • If we have a handle to an SP, when connecting to a bootstrap-agent dropshot server, we will spawn a (temporary) sprockets client-side proxy and connect to it instead of to the target dropshot server directly.

Without a handle to an SP (or prior to this PR), connections from bootstrap-agent-to-bootstrap-agent to init sleds were direct:

graph TD
    A[bootstrap-agent] -->|bootstrap network| B[bootstrap-agent dropshot server]
Loading

After this PR and with a handle to an SP, connections between bootstrap agents now flow through sprockets proxies on localhost:

graph TD
    A[bootstrap-agent] -->|loopback| B(sprockets-proxy client)
    B -->|bootstrap network| C(sprockets-proxy server)
    C -->|loopback| D[bootstrap-agent dropshot server]
Loading

The use of TCP over localhost has (potentially severe) security implications; they're noted in a TODO-security comment in sled-agent/src/bin/sled-agent.rs where we set up the listen address for dropshot, but I'd be happy to lift them to a github issue if that would be better.

I tried to include sufficient logging to follow the proxy connections, but it still leaves something to be desired since dropshot logs only include the connection coming from the proxy in front of it (on localhost). Here's a snippet from starting up the control plane for the first time on two VMs, helios1 and helios2, between when RSS determines the plan and when the two bootstrap agents receive the sled agent requests and begin starting them:

helios1 (where RSS runs):

[2022-05-27T15:58:25.417243705Z]  INFO: SledAgent/RSS/1203 on helios1: Plan written to storage
[2022-05-27T15:58:25.417953006Z]  INFO: SledAgent/BootstrapAgentRssHandler/1203 on helios1: Received initialization request from RSS (target_sled=[fdb0:5254:e4:589f::1]:12346)
    request: SledAgentRequest { subnet: Ipv6Subnet { net: Ipv6Net(Ipv6Network { addr: fd00:1122:3344:101::, prefix: 64 }) } }
[2022-05-27T15:58:25.421191274Z]  INFO: SledAgent/BootstrapAgentRssHandler/1203 on helios1: Sending request to peer agent via sprockets proxy (sprockets_proxy=[::1]:55077, peer=[fdb0:5254:e4:589f::1]:12346)
[2022-05-27T15:58:25.422068466Z] DEBUG: SledAgent/BootstrapAgentRssHandler/1203 on helios1: client request (BootstrapAgentClient=http://[::1]:55077, body=Some(Body), uri=http://[::1]:55077/start_sled, method=PUT)
[2022-05-27T15:58:25.428789402Z]  INFO: SledAgent/BootstrapAgentRssHandler/1203 on helios1: Received initialization request from RSS (target_sled=[fdb0:5254:8a:8c1c::1]:12346)
    request: SledAgentRequest { subnet: Ipv6Subnet { net: Ipv6Net(Ipv6Network { addr: fd00:1122:3344:102::, prefix: 64 }) } }
[2022-05-27T15:58:25.437910465Z]  INFO: SledAgent/BootstrapAgentRssHandler/1203 on helios1: Sending request to peer agent via sprockets proxy (sprockets_proxy=[::1]:45838, peer=[fdb0:5254:8a:8c1c::1]:12346)
[2022-05-27T15:58:25.439813844Z] DEBUG: SledAgent/BootstrapAgentRssHandler/1203 on helios1: client request (BootstrapAgentClient=http://[::1]:45838, body=Some(Body), uri=http://[::1]:45838/start_sled, method=PUT)
[2022-05-27T15:58:25.441400725Z] DEBUG: SledAgent/BootstrapAgentRssHandler/1203 on helios1: accepted connection (BootstrapAgentClientSprocketsProxy=[fdb0:5254:e4:589f::1]:12346, addr=[::1]:35121)
[2022-05-27T15:58:25.442681917Z] DEBUG: SledAgent/BootstrapAgentRssHandler/1203 on helios1: accepted connection (BootstrapAgentClientSprocketsProxy=[fdb0:5254:8a:8c1c::1]:12346, addr=[::1]:54020)
[2022-05-27T15:58:25.443910963Z] DEBUG: SledAgent/sprockets-proxy (Bootstrap)/1203 on helios1: accepted connection (addr=[fdb0:5254:8a:8c1c::1]:43834)
[2022-05-27T15:58:25.444767204Z]  INFO: SledAgent/dropshot (Bootstrap)/1203 on helios1: accepted connection (local_addr=[::1]:34196, remote_addr=[::1]:54778)
[2022-05-27T15:58:25.457097147Z]  INFO: SledAgent/BootstrapAgent/1203 on helios1: Loading Sled Agent: SledAgentRequest { subnet: Ipv6Subnet { net: Ipv6Net(Ipv6Network { addr: fd00:1122:3344:102::, prefix: 64 }) } } (server=fb0f7546-4d46-40ca-9d56-cbb810684ca
7)
[2022-05-27T15:58:25.457642039Z]  INFO: SledAgent/1203 on helios1: setting up sled agent server

helios2:

[2022-05-27T15:58:25.408747892Z] DEBUG: SledAgent/sprockets-proxy (Bootstrap)/873 on helios2: accepted connection (addr=[fdb0:5254:8a:8c1c::1]:36552)
[2022-05-27T15:58:25.409870173Z]  INFO: SledAgent/dropshot (Bootstrap)/873 on helios2: accepted connection (local_addr=[::1]:62291, remote_addr=[::1]:37219)
[2022-05-27T15:58:25.432786801Z]  INFO: SledAgent/BootstrapAgent/873 on helios2: Loading Sled Agent: SledAgentRequest { subnet: Ipv6Subnet { net: Ipv6Net(Ipv6Network { addr: fd00:1122:3344:101::, prefix: 64 }) } } (server=fb0f7546-4d46-40ca-9d56-cbb810684ca7
)
[2022-05-27T15:58:25.434327107Z]  INFO: SledAgent/873 on helios2: setting up sled agent server

Setting up the above requires using thing-flinger to (among other things) distribute config-sp.toml files so all nodes know to simulate SP/RoTs, which are required to establish sprockets sessions. That happens in sled-agent-overlay-files and is included in this PR.

My setup is having trouble starting nexus, but I believe that to be a VM networking issue and not related to the changes in this PR, given the above logs and the lack of changes to nexus/service-related code. I'm going to continue to debug that but believe this code is ready to review even without tracking that all the way down. Edit: This was fixed by #1132.

Copy link
Contributor

@andrewjstone andrewjstone left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

// running plain HTTP and blindly trusting all connections from
// localhost. We have a similar sprockets proxy on the client side,
// where the proxy blindly trusts all connections from localhost
// (although the client-side proxy only runs while is being made,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo (missing word?): while is being made

let proxy_addr = proxy.local_addr();

let proxy_task = tokio::spawn(async move {
// TODO-robustness `proxy.run()` only fails if `accept()`ing on our
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Panicking seems totally reasonable to me.

// sessions, so we'll have the bootstrap dropshot server listen on
// `bootstrap_address` (and no sprockets proxy).
//
// TODO-security: With this configuration, dropshot itself is
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably should lift this to a Github issue as you mentioned in the PR description; I don't think we want to lose track of this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 I'll open an issue as a part of merging this PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Merged and opened #1161

// something other than TCP that we can lock down, or abandoning
// dropshot and using a bespoke protocol over a raw
// sprockets-encrypted TCP connection.
let (bootstrap_dropshot_addr, sprockets_proxy_bind_addr) =
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: These two values seem really tightly coupled; I wonder if they should be a distinct type.

That being said, I understand passing things through the ConfigDropshot doesn't make that trivial, so we can punt on this.

Comment on lines 132 to 142
// Ensure we have the global zone IP address we need for the SP.
let data_link = if let Some(link) = sled_config.data_link.clone() {
link
} else {
Dladm::find_physical()?
};
Zones::ensure_has_global_zone_v6_address(data_link, *sp_addr, "simsp")
.map_err(|err| SpError::EnsureGlobalZoneAddressError {
addr: *sp_addr,
err,
})?;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As of #1066 , I've moved most of the VNIC / address allocation to happen over an etherstub instead of a physical data link. motivation here.

As a result, most of our addresses are being allocated over these etherstubs; there's an example here:

let etherstub = Dladm::create_etherstub().map_err(|e| {
BootstrapError::SledError(format!(
"Can't access etherstub device: {}",
e
))
})?;
let etherstub_vnic =
Dladm::create_etherstub_vnic(&etherstub).map_err(|e| {
BootstrapError::SledError(format!(
"Can't access etherstub VNIC device: {}",
e
))
})?;
Zones::ensure_has_global_zone_v6_address(
etherstub_vnic,
address,
"bootstrap6",
)
.map_err(|err| BootstrapError::BootstrapAddress { err })?;

Could this sp_addr also be allocated on the etherstub link?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I expect so; I'll rebase to confirm. For now I haven't been testing the management network side of the simulated SPs at all (and am running a test config without any networking), since we only need the simulated RoT to do sprockets things. This will be revisited as we move back to MGS and start integrating it into the control plane, at which point it will need to access the (simulated) SPs over UDP.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed in 02c2f57; we not only could change this allocation, but had to: Zones::ensure_has_global_zone_v6_address() now takes an EthernetVnic as its first arg, so the previous code allocating on the physical link no longer compiled.

@jgallagher jgallagher merged commit 01764e0 into main Jun 6, 2022
@jgallagher jgallagher deleted the sled-agent-sprockets branch June 6, 2022 17:24
leftwo pushed a commit that referenced this pull request Feb 9, 2024
Crucible changes:
Remove unused fields in IOop (#1149)
New downstairs clone subcommand. (#1129)
Simplify the do_work_task loop (#1150)
Move `Guest` stuff into a module (#1125)
Bump nix to 0.27.1 and use new safer Fd APIs (#1110)
Move `FramedWrite` work to a separate task (#1145)
Use fewer borrows in ExtentInner API (#1147)
Update Rust crate reedline to 0.28.0 (#1141)
Update Rust crate tokio to 1.36 (#1143)
Update Rust crate slog-bunyan to 2.5.0 (#1139)
Update Rust crate rayon to 1.8.1 (#1138)
Update Rust crate itertools to 0.12.1 (#1137)
Update Rust crate byte-unit to 5.1.4 (#1136)
Update Rust crate base64 to 0.21.7 (#1135)
Update Rust crate async-trait to 0.1.77 (#1134)
Discard deferred msgs (#1131)
Minor Downstairs cleanup (#1127)
Update test_fail_live_repair to support pstop (#1128)
Ignore client messages after stopping the IO task (#1126)
Move client IO task into a struct (#1124)
Bump Rust to 1.75 and fix new Clippy lints (#1123)

Propolis changes:
PHD: convert to async (#633)
PHD: assume specialized Windows images (#636)
propolis-standalone-config needn't be a crate
standalone: Use tar for snapshot/restore
phd: use latest "lab-2.0-opte" target, not a specific version (#637)
PHD: add tests for migration of running processes (#623)
PHD: fix `cargo xtask phd` tidy not doing anything (#630)
PHD: add documentation for `cargo xtask phd` (#629)
standalone: improve virtual device creation errors (#632)
phd: add Windows Server 2019 guest adapter (#627)
PHD: add `cargo xtask phd` to make using PHD nicer (#619)
leftwo added a commit that referenced this pull request Feb 9, 2024
Crucible changes:
Remove unused fields in IOop (#1149)
New downstairs clone subcommand. (#1129)
Simplify the do_work_task loop (#1150)
Move `Guest` stuff into a module (#1125)
Bump nix to 0.27.1 and use new safer Fd APIs (#1110) Move `FramedWrite`
work to a separate task (#1145) Use fewer borrows in ExtentInner API
(#1147)
Update Rust crate reedline to 0.28.0 (#1141)
Update Rust crate tokio to 1.36 (#1143)
Update Rust crate slog-bunyan to 2.5.0 (#1139)
Update Rust crate rayon to 1.8.1 (#1138)
Update Rust crate itertools to 0.12.1 (#1137)
Update Rust crate byte-unit to 5.1.4 (#1136)
Update Rust crate base64 to 0.21.7 (#1135)
Update Rust crate async-trait to 0.1.77 (#1134)
Discard deferred msgs (#1131)
Minor Downstairs cleanup (#1127)
Update test_fail_live_repair to support pstop (#1128) Ignore client
messages after stopping the IO task (#1126) Move client IO task into a
struct (#1124)
Bump Rust to 1.75 and fix new Clippy lints (#1123)

Propolis changes:
PHD: convert to async (#633)
PHD: assume specialized Windows images (#636)
propolis-standalone-config needn't be a crate
standalone: Use tar for snapshot/restore
phd: use latest "lab-2.0-opte" target, not a specific version (#637)
PHD: add tests for migration of running processes (#623) PHD: fix `cargo
xtask phd` tidy not doing anything (#630) PHD: add documentation for
`cargo xtask phd` (#629) standalone: improve virtual device creation
errors (#632) phd: add Windows Server 2019 guest adapter (#627)
PHD: add `cargo xtask phd` to make using PHD nicer (#619)

Co-authored-by: Alan Hanson <alan@oxide.computer>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants