-
Notifications
You must be signed in to change notification settings - Fork 687
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
Add v3 onion support to tor-hidden-services ansible role #4652
Conversation
(Since it's a draft PR and cannot be merged anyway, I've removed "DO NOT MERGE" from the PR title) |
While working on In v3, we have to create at least 2 different set of @redshiftzero Is it okay if I use same set of keys for both |
@kushaldas I think we should use separate keys where possible, so separate keys for the SSH services on app and mon |
0e920a0
to
07fed0c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you provide a test plan, @kushaldas? I haven't yet tested in VMs, only provided a visual review as a first pass. Take a look at the duplication and see if you can reduce it, based on the previously implemented v2 logic. Happy to lend a hand or collaborate directly on this branch if you'd prefer.
public/private key pair. | ||
""" | ||
secret_key_path = os.path.join(args.ansible_path, | ||
"tor_v3_keys.json") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just as we currently have two discrete files on the Admin Workstation for the v2 auth info, it'd be great to have the same for the v3 info. Doing so would simplify the lookup logic required in the dynamic-inventory script (not yet implemented in this PR), as well. Perhaps the function should receive hostname=None
, and select the files that way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel that one file for admin workstation with all 3 different key pairs (journalist, ssh app, and ssh mon) and a file for journalist workstations (only with the journalist keypair) is simpler. Also, this is only for the key information, if we want, we can also remove the ths
files all together and just the .onion
address from the JSON files iteself (we have to add them there).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having taken a closer look at the keygen logic, we're still going to need separate files for the dynamic-inventory support (OK to defer to #4629). With the v2 logic, if-and-only-if the -ths
files are present on the Admin Workstation, then Onion URLs are used for the SSH connection. Since those -ths
files are created on the Admin Workstation at the end of the install process, the logic is sound. For the v3 keygen logic, however, we need a way to denote whether the corresponding Onion URLs should be used for the SSH connection.
I suggest moving the keygen logic into Ansible via a script, so that the JSON file does not exist when Ansible builds the SSH connection, meaning local IPv4 addresses (or v2 Onion URLs) will be used. At the end of the run, we can sprinkle in appropriate -v3-ths
files back onto the Admin Workstation.
We cannot relegate the v3 keygen logic solely to the securedrop-admin
init, because that's only relevant for Tails environments, which means developer staging VMs will not have v3 connectivity.
@@ -20,6 +20,17 @@ tor_instances: | |||
- service: journalist | |||
filename: app-journalist-aths | |||
|
|||
tor_instances_v3: | |||
- "{{ {'service': 'sshv3', 'filename': 'app-sshv3-aths'} if enable_ssh_over_tor else [] }}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The else []
causes an empty list here—is that intentional? The other elements of tor_instances_v3
are dicts, not lists. Haven't tested functionally yet to observe an error here, but it seems inconsistent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I copied that from the above lines in the same file https://github.com/freedomofpress/securedrop/blame/07fed0c56e89d7edb006a7aa9e0f850d3d516216/install_files/ansible-base/group_vars/securedrop_application_server.yml#L17 Seems to be added by @msheiny 2 years ago.
install_files/ansible-base/roles/restrict-direct-access/tasks/fetch_tor_config.yml
Outdated
Show resolved
Hide resolved
install_files/ansible-base/roles/restrict-direct-access/tasks/fetch_tor_config.yml
Outdated
Show resolved
Hide resolved
- "v3_onion_services|default(False)" | ||
- inventory_hostname == 'app' | ||
tags: | ||
- tor |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The key-management tasks here are largely duplicated, with conditional checks for determining whether app or mon is the current host. Since the tasks will by default run against both hosts, and the facts will be set uniquely per-host, we don't need the duplication.
@@ -0,0 +1 @@ | |||
descriptor:x25519:{{ tor_v3_app["app_ssh_key"] }} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As above, these templates don't need to be unique per-host—see for reference the existing v2 logic:
securedrop/install_files/ansible-base/roles/restrict-direct-access/tasks/fetch_tor_config.yml
Lines 21 to 31 in 20cbd52
- name: Write Tor hidden service hostname files to Admin Workstation. | |
local_action: | |
module: template | |
dest: "{{ role_path }}/../../{{ item.item.filename }}" | |
src: ths_config.j2 | |
# Local action, so we don't want elevated privileges | |
become: no | |
with_items: "{{ tor_hidden_service_hostname_lookup.results }}" | |
tags: | |
- tor | |
- admin |
Appended two commits, aiming to simplify the keypair-management logic within the Ansible roles. Please take a look, @kushaldas, and see if you agree that the terser version is suitable. While working on this, I noticed that the branch here is outdated; it doesn't include the related Tor logic introduced in #4648:
If you agree the added commits are work keeping, please rebase on top of latest develop, so we're testing with the most recently merged work. The most important outstanding changes in my view are:
Based on the discussion in #4628 (comment), it looks like you've already tried to the script-based approach. Let's try to get that working again. See example below for a slightly modified version of your script. If we can adjust the calls to get it working with the currently used version of cryptography, great, otherwise let's make sure to bump the requirement in the same contexts Ansible is used (i.e. also dev envs). Example script generate-tor-v3-keypairs
Once we have passable keypair-and-service generation in this PR, we can discuss specifics on the Tails-specific integration in #4629. Let me know your thoughts on the above, @kushaldas. |
@conorsch I am okay with the approach you mentioned here. What should be the next step? |
Oops, my mistake: I hadn't actually pushed! The two new commits are now present on the branch, see fea52e0 & 92e0949.
@kushaldas Recapping my comment above, the next steps should be:
Please handle those tasks, and ping me when you feel the branch is ready for another look! |
6143233
to
8f64cf4
Compare
@conorsch Last time when I tried, I could not do that the above in a nice |
What about tweaking the dev initialization entry-points to call a subset of securedrop admin scripts first? I don't think ansible is the right answer to every scriptable problem. Ansible is really good at running a bunch of tasks remotely. This task is run locally and would benefit from more in-depth unit testing. Recall that in the past at one point, the admin scripting was in ansible but that was deemed unmaintainable and was moved to python. |
The currently implemented securedrop-admin strategy cannot configure v3 URLs when testing against VMs, so the invocation must change. It needn't be pure Ansible—simply calling a script makes sense—but at no point other than Tails-based QA testing are devs regularly invoking the securedrop-admin logic. The current script logic uses python If we moved to a leaner method like bash, we might wind up with more portable keygen logic, but that doesn't seem worthwhile—we'd have to be careful about system deps like openssl versions. As far as what calls the keygen logic script, the most important attributes are 1) it's automatic, so devs don't forget; 2) the same process is used on dev/admin workstations, as far as possible. |
Current means? The branch I pushed last week, did it amazingly :) |
Also, we can just make the dynamic inventory to call the similar python function to get key pairs while doing from |
8f64cf4
to
6fc3763
Compare
@conorsch Added the changes requested. When I tried the scrip way, I could not find a way to get the correct |
I could have been more clear: the current strategy (accurate as of today on this branch) fails to configure v3 URLs on staging VMs unless a Tails VM is also used. That means that
That sounds like a consequence of the crytography version bump. Although you added the new cryptography version to Testing locally, I was able to invoke the keygen script successfully via Ansible using the following command:
After cleaning up the aforementioned linting errors, that script executes well, and returns JSON (albeit escaped in the interactive terminal, since Ansible renders task results as JSON by default). So, for next steps, please do the following:
Based on previous discussion, there may be outstanding questions regarding the implementation of step 5. Please set aside some time to give it your best shot. If you get stuck and it makes sense for us to pair on Ansible work for a bit, we can find a time to do so. |
fbe7c7c
to
78e524e
Compare
app-staging.yml is what is used in the test_tor_hidden_services tests, the variables removed in this diff seem to be just unnecessary duplicated/confusing
The securedrop-admin virtualenv is still py2, but the rest of the project, including developer env, uses py3. Let's modify just the keygen logic for v3 URLs to work under both Python 2 & Python 3.
Two changes here. First, we remove the sys.exit() calls inside the v3 keygen logic. Those worked well enough when the script is invoked directly via the subcommand, but causes the `./securedrop-admin install` exit to quit before calling out to Ansible. We replace the sys.exit calls with `return 0`, since the parent function expects an exit code to be returned, and passes this to the shell. Second, we stop calling the keygen logic automatically as part of the install action. If anything, it'd be more appropriate to configure those values as part of `sdconfig`, but since the generation depends on the site config already being evaluted (i.e. v3_onion_services=True), we shouldn't automatically generate keys before inspecting the config.
The service name is different for v2/v3 Onion services; the v3 config was missing the "v3" suffix on the end of the service name, causing the install to fail when writing.
Implementing suggestion by @zenmonkeykstop, to format the files directly on the Admin Workstation in the format required for ingestion by the `tailsconfig` logic in securedrop-admin. Modified the filename for the journalistv3 service, so that the existing "if filename ends with '-aths'" logic will work, as with the SSH services. h/t to @redshiftzero for an assist on the Jinja.
this seems to be timing out a bunch lately in CI, giving it another 5 minutes
h/t to @conorsch for pointing this out
Let's name the v3 client auth info with a compatible filename for use with the tor services on the Admin Workstation. Simplifies the tailsconfig logic to move the files, rather than rename them according to a map.
If an instance has multiple Administrators, and one chooses to enable v3, we should detect that scenario and fail early to avoid destroying the previously configured client auth info.
We're aiming to fail early if an Admin runs the install action against a server with v3 configured, but without having run sdconfig to enable v3 (indicates multiple Admins). Updated the monstrous filter line to pull out the booleans, then inspect that list in an assert statement. Seems to be working as expected, will test with multiple configuration paths prior to squashing. Better support for "staging" scenario, which has v3_onion_services=true, but enable_ssh_over_tor=false, so mon-staging was failing the check. Updated to accommodate. If no onions exist, don't fail: we're about to set them up!
Checks that BOTH of the following conditions are NOT true: * v3_onion_services=false * v3 services exist on remote host If both are true, that's likely the result of a misconfiguration. This logic handles the prod use case of v2 enabled, also enabling v3. It hasn't yet been tested with ssh-over-LAN, we'll likely need to modify the restrict-direct-access role to accommodate.
The dynamic logic to accommodate for SSH-over-LAN includes the "restrict-direct-access" role, which assumes that Onion Services already exist on the remote host. That's not the case when migrating from v2 to v3 Onion services, so let's override the dynamic include logic to instruct the role *not* to wait for the hostname files to be created. Later in the playbook, the restrict-direct-access role will run without the override, fetching back the client auth config that now exists, since the tor role will also have run by this point.
3d86cd2
to
f24ffc0
Compare
Changes requested by @zenmonkeykstop have been addressed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Re-approving. Satisfied with behavior in the following scenarios (all using Tails VM against prod VMs):
Scenario 1
- Clean install with v2-only.
- Enable v3 (in addition to v2), install again.
Scenario 2
- Clean install with v2-only and ssh-over-lan
- Enable v3 (in addition to v2), preserve ssh-over-lan, install again.
Scenario 3
- Clean install with v3-only
- [did not run a second install, since connection depends on Adds support for v3 Onion urls to ./securedrop-admin tailsconfig` #4675]
CI is passing, as well, so calling this one a wrap. Thanks for all your hard work on this one, @kushaldas & @redshiftzero!
Status
Ready for review
Description of Changes
Fixes #4628
Fixes #4667
Started adding related Ansible changes to have v3 onion services (including the authenticated ones).
Testing
v3 only
./securedrop-admin install
on a already installed system.For both the options above, make the following two changes in
install_files/ansible-base/group_vars/all/site-specific
For this case:
v2/v3 alongside
For this:
app
andmon
serversv2 only
There is also the third point to test which is not adding
v2_onion_services
orv3_onion_services
tosite-specific
and instead the default values (v2 on, v3 off).This should keep the current v2 systems as it is, and no v3 details should be generated in the servers.
Deployment
Any special considerations for deployment? Consider both:
Checklist
If you made changes to the server application code:
make lint
) and tests (make -C securedrop test
) pass in the development containerIf you made changes to
securedrop-admin
:make -C admin test
) pass in the admin development containerIf you made changes to the system configuration:
If you made non-trivial code changes:
If you made changes to documentation:
make docs-lint
) passed locally