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

ssh_util: Handle sshd_config.d folder #1618

Merged
merged 8 commits into from Aug 5, 2022
Merged

Conversation

aciba90
Copy link
Contributor

@aciba90 aciba90 commented Jul 25, 2022

Proposed Commit Message

ssh_util: Handle sshd_config.d folder

Write sshd config to /etc/ssh/sshd_config.d/00-cloud-init.conf
if the sshd_config sources sshd_config.d

LP: #1968873

Additional Context

SC-1172
LP: #1968873

In order to ease upgrading openssh-server, write out sshd_config
into a separated cloud-init conf file with high priority under
/etc/ssh/sshd_config.d/00-cloud-init.conf.

This fixes #1968873 in main and will be SRUed to focal, impish
and focal.

Test Steps

cat <<EOF > /tmp/user-data
#cloud-config
ssh_pwauth: true
password: asdf
EOF

lxc launch ubuntu:focal ff --config=user.user-data="$(cat /tmp/user-data)"
lxc exec ff -- cloud-init status --wait

$ lxc exec ff -- grep -rn 'PasswordAuthentication ' /etc/ssh/sshd_config /etc/ssh/sshd_config.d
/etc/ssh/sshd_config:58:PasswordAuthentication no
/etc/ssh/sshd_config.d/00-cloud-init.conf:1:PasswordAuthentication yes

# Previously
# /etc/ssh/sshd_config:58:PasswordAuthentication yes

$ lxc exec ff -- grep -ri 'Writing to /etc/ssh/sshd_config - wb' /var/log/cloud-init.log
# Expect no output

# Previously:
# 2022-07-26 10:04:33,269 - util.py[DEBUG]: Writing to /etc/ssh/sshd_config - wb: [644] 3288 bytes

$ lxc exec ff -- grep -ri 'Writing to /etc/ssh/sshd_config.d' /var/log/cloud-init.log
2022-07-26 09:51:10,076 - util.py[DEBUG]: Writing to /etc/ssh/sshd_config.d/00-cloud-init.conf - ab: [644] 0 bytes
2022-07-26 09:51:10,076 - util.py[DEBUG]: Writing to /etc/ssh/sshd_config.d/00-cloud-init.conf - wb: [644] 27 bytes


lxc exec ff -- apt-get udpate
lxc exec ff -- apt-get upgrade -y
$ lxc exec ff -- do-release-upgrade -d
# A prompt does appear:

# A new version (/tmp/tmp.dAvrCWldyw) of configuration file /etc/ssh/sshd_config is available, but the version installed currently has been locally modified.
#
# What do you want to do about modified configuration file sshd_config?
# ...

# click on show diff
# the diff must not contain a diff with `PasswordAuthentication`

# Note: `/etc/ssh/sshd_config` still has modifications but not made by `cloud-init`.

lxc exec ff -- apt-get purge -y cloud-init
$ lxc exec ff -- ls /etc/ssh/sshd_config.d/00-cloud-init.conf 
ls: cannot access '/etc/ssh/sshd_config.d/00-cloud-init.conf': No such file or directory

Checklist:

  • My code follows the process laid out in the documentation
  • I have updated or added any unit tests accordingly
  • I have updated or added any documentation accordingly

@aciba90 aciba90 changed the title Sshd ssh_util: Handle sshd_config.d folder Jul 25, 2022
@aciba90 aciba90 force-pushed the sshd branch 2 times, most recently from 7d45889 to 31b38c6 Compare July 26, 2022 07:57
@aciba90 aciba90 marked this pull request as ready for review July 26, 2022 07:58
@aciba90
Copy link
Contributor Author

aciba90 commented Jul 26, 2022

FYI, @toabctl, here is the sshd_config fix.

@aciba90
Copy link
Contributor Author

aciba90 commented Jul 26, 2022

There is another reference to /etc/ssh/sshd_config in tools/uncloud-init#L126.

I guess that tool is a development tool and in order to minimize the SRU patch, we can defer its fix to a follow-up PR. Is that right? @blackboxsw, @holmanb, @TheRealFalcon.

@aciba90
Copy link
Contributor Author

aciba90 commented Jul 26, 2022

There is another reference to /etc/ssh/sshd_config in tools/uncloud-init#L126.

I guess that tool is a development tool and in order to minimize the SRU patch, we can defer its fix to a follow-up PR. Is that right? @blackboxsw, @holmanb, @TheRealFalcon.

After a team discussion, we decided to not extend /tools/uncloud-init as it had no activity since 3 years and might be removed.

What we want to extend is the post-remove deb hook during purge to clean-up 99-cloud-init.conf. I mark this PR as Draft until done.

@aciba90 aciba90 marked this pull request as draft July 26, 2022 14:47
@aciba90 aciba90 marked this pull request as ready for review July 26, 2022 18:19
@aciba90
Copy link
Contributor Author

aciba90 commented Jul 26, 2022

packages/debian/cloud-init.postrm added and tested. This PR is ready to be reviewed.

cloudinit/ssh_util.py Outdated Show resolved Hide resolved
cloudinit/ssh_util.py Outdated Show resolved Hide resolved
Copy link
Member

@toabctl toabctl left a comment

Choose a reason for hiding this comment

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

LGTM. thanks!

@blackboxsw blackboxsw self-assigned this Aug 4, 2022
Copy link
Collaborator

@blackboxsw blackboxsw left a comment

Choose a reason for hiding this comment

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

This looks really good @aciba90 thank you much for putting this together.
Minor comments on:

  • file permissions on the config parts file
  • using prefix 50-cloud-init.conf
  • integration tests for the file emitted

otherwise +1.

cloudinit/ssh_util.py Outdated Show resolved Hide resolved
cloudinit/ssh_util.py Outdated Show resolved Hide resolved
packages/debian/cloud-init.postrm Outdated Show resolved Hide resolved
tests/unittests/config/test_cc_ssh.py Outdated Show resolved Hide resolved
@aciba90
Copy link
Contributor Author

aciba90 commented Aug 5, 2022

This looks really good @aciba90 thank you much for putting this together. Minor comments on:

* file permissions on the config parts file

* using prefix 50-cloud-init.conf

* integration tests for the file emitted

otherwise +1.

Addressed. Thanks, @blackboxsw, for the review and constructive comments. This is ready to be reviewed.

@blackboxsw
Copy link
Collaborator

blackboxsw commented Aug 5, 2022

FYI: @stevebeattie & @setharnold for general awareness of security-related behavior changes in cloud-init sshd_config.d.

Copy link
Collaborator

@blackboxsw blackboxsw left a comment

Choose a reason for hiding this comment

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

LGTM. Thanks for the permissions fixes @aciba90. I'm good to land this EOD today.

@aciba90
Copy link
Contributor Author

aciba90 commented Aug 8, 2022

Is the idea to allow supporting multiple sshds on a system? eg, one for PAM-based authentication on usual port 22, and one for unprivileged access on another port without PAM, just checking a key? or perhaps different PAM configurations? I'm not entirely sure I see the use-cases, but so long as you're content that only trusted inputs are supplied, so eg fname isn't set to ../../../../etc/nologin or similar, it all looked fine enough.

Thanks

The idea is to not modify /etc/ssh/shhd_config file in systems where /etc/ssh/shhd_config does source /etc/ssh/shhd_config.d/ (focal, jammy, kinetic), because this file is distributed via open-sshd package and want users to have a seamless do-release-upgrade process.

In respect to fname, we define it as /etc/ssh/sshd_config/50-cloud-init.conf and the function is for internal usage only.

@aciba90 aciba90 deleted the sshd branch August 8, 2022 14:45
@setharnold
Copy link

Okay, cool, so it's impossible for untrusted code to ever call update_ssh_config(foo, fname="../../../etc/logrotate") for example?

Thanks

@aciba90
Copy link
Contributor Author

aciba90 commented Aug 10, 2022

Okay, cool, so it's impossible for untrusted code to ever call update_ssh_config(foo, fname="../../../etc/logrotate") for example?

Thanks

Well, we would have to define what is untrusted code to answer that. What is clear is that this PR does not introduce new attack vectors, as the function already accepted fname as a pointer to a file to write config in. We are just extending that function to verify the case where a .d folder exists. Please, let me know any concern / clarification. Thanks.

@holmanb
Copy link
Member

holmanb commented Aug 10, 2022

@aciba90 @setharnold

Okay, cool, so it's impossible for untrusted code to ever call update_ssh_config(foo, fname="../../../etc/logrotate") for example?

I think the answer to this is technically "no it is not impossible". A (root) user could technically write a 3rd party module (not trusted, by some definitions) that uses this function, insert the module into a root-only writable directory on the fs where config modules live, configure cloud-init to load this module (in their root-only writable cloud.cfg), and cloud-init would would technically run untrusted code that calls update_ssh_config(foo, fname="../../../etc/logrotate").

However this isn't an escalation issue because every step of that has Posix permissions preventing a non-root user from doing it.

So I agree with what @aciba90 said: it depends on how you define untrusted. And I don't think this change poses a problem, because in the default case the code executing this is trusted.

@setharnold
Copy link

I think I was thinking more along the lines of an ISP-supplied "easy deployment" sort of web interface that might take a "machine name" or "service name" sort of field and use it in surprising ways.

If you're content then I'm content :D Thanks!

@ani-sinha
Copy link
Contributor

re: /etc/ssh/sshd_config.d/50-cloud-init.conf generated by cloud-init I see it is removed using packages/debian/cloud-init.postrm . Since the package manager does not install the conf, could we not have cleaned it up as a part of "cloud-init clean" operation?

@ani-sinha
Copy link
Contributor

The reason I ask is that for centos/rhel, if we took similar approach, we would have to remove it from the rpm spec file. Instead we could have a common place to remove such conf files, @blackboxsw

@ani-sinha
Copy link
Contributor

The reason I ask is that for centos/rhel, if we took similar approach, we would have to remove it from the rpm spec file. Instead we could have a common place to remove such conf files, @blackboxsw

For example, we could we not remove it as a part of cloud-init clean or some such? Today it removes only log files.

@aciba90
Copy link
Contributor Author

aciba90 commented Aug 22, 2023

Thanks, @ani-sinha, for making cloud-init better.

I think it is reasonable to expect cloud-init clean to remove the file. Could you please create an issue referencing this PR?

Another instance of this problem with a different file: #3240

@ani-sinha
Copy link
Contributor

Thanks, @ani-sinha, for making cloud-init better.

I think it is reasonable to expect cloud-init clean to remove the file. Could you please create an issue referencing this PR?

Another instance of this problem with a different file: #3240

I have some reservations about this after thinking. When cloud-init clean removes log files its harmless. But if config files that are produced by cloud-init are removed, will that create some inconsistency particularly if cloud-init init does not recreate them?

@aciba90
Copy link
Contributor Author

aciba90 commented Aug 22, 2023

Per cli.html#clean and #3240 (comment), I understand that files that are dynamically created by cloud-init at runtime are okay to be removed by cloud-init clean.

But if you think this in not required, then do not create the issue, thanks.

@ani-sinha
Copy link
Contributor

Per cli.html#clean and #3240 (comment), I understand that files that are dynamically created by cloud-init at runtime are okay to be removed by cloud-init clean.

But if you think this in not required, then do not create the issue, thanks.

Right now the clean command only cleans artefacts from ’/var/lib/cloud’ and the cli documentation also says so. Adding config files to it would be something new and I am not sure if it's safe. If we do this the cli documentation also needs updating. Hence I need inputs from cloud-init maintainers . I would be happy to send a PR if it seems ok to do it .

@aciba90
Copy link
Contributor Author

aciba90 commented Aug 22, 2023

By safe, do you mean software security? cloud-init clean would be able to remove the conf file only if the user executing the command has the appropriated permissions to do so, and if that is true, then the user could remove / modify that file by other means.

If we do this the cli documentation also needs updating. Hence I need inputs from cloud-init maintainers.

Yes, the documentation should be updated in that case. Something like:

Remove cloud-init artifacts from /var/lib/cloud and config files (best effort) to simulate a clean instance. On reboot, cloud-init will re-run all stages as it did on first boot.

@ani-sinha
Copy link
Contributor

By safe, do you mean software security?

No what I mean is that there might be some inconsistency if ‘cloud-init init‘ doesn't recreate all the config files that were present before cleaning. The inconsistency might break cloud-init functionality.

@ani-sinha
Copy link
Contributor

By safe, do you mean software security?

No what I mean is that there might be some inconsistency if ‘cloud-init init‘ doesn't recreate all the config files that were present before cleaning. The inconsistency might break cloud-init functionality.

@blackboxsw what do you think?

ani-sinha added a commit to ani-sinha/cloud-init that referenced this pull request Aug 24, 2023
cloud-init generates several config files today that are not cleaned as a part
of `cloud-init clean` operation. For example, cloud-init uses
/etc/ssh/sshd_config.d/50-cloud-init.conf to configure ssh daemon which is then
left uncleaned. This change adds a new option `cloud-init clean --config` that
would clean up these config files as well. Additionally, the cli documentation
has also been updated to document this new option.

Reference:
canonical#1618
Fixes: canonicalGH-3240

Signed-off-by: Ani Sinha <anisinha@redhat.com>
ani-sinha added a commit to ani-sinha/cloud-init that referenced this pull request Aug 24, 2023
cloud-init generates several config files today that are not cleaned as a part
of `cloud-init clean` operation. For example, cloud-init uses
`/etc/ssh/sshd_config.d/50-cloud-init.conf` to configure ssh daemon which is then
left uncleaned. This change adds a new option `cloud-init clean --config` that
would clean up these config files as well. Additionally, the cli documentation
has also been updated to document this new option.

Reference:
canonical#1618
Fixes: canonicalGH-3240

Signed-off-by: Ani Sinha <anisinha@redhat.com>
ani-sinha added a commit to ani-sinha/cloud-init that referenced this pull request Aug 24, 2023
cloud-init generates several config files today that are not cleaned as a part
of `cloud-init clean` operation. For example, cloud-init uses
`/etc/ssh/sshd_config.d/50-cloud-init.conf` to configure ssh daemon which is then
left uncleaned. This change adds a new option `cloud-init clean --configs` that
would clean up these config files as well. Additionally, the cli documentation
has also been updated to document this new option.

Reference:
canonical#1618
Fixes: canonicalGH-3240

Signed-off-by: Ani Sinha <anisinha@redhat.com>
ani-sinha added a commit to ani-sinha/cloud-init that referenced this pull request Aug 25, 2023
cloud-init generates several config files today that are not cleaned as a part
of `cloud-init clean` operation. For example, cloud-init uses
`/etc/ssh/sshd_config.d/50-cloud-init.conf` to configure ssh daemon which is then
left uncleaned. This change adds a new option `cloud-init clean --configs` that
would clean up these config files as well. Additionally, the cli documentation
has also been updated to document this new option.

Reference:
canonical#1618

Fixes: canonicalGH-3240

Signed-off-by: Ani Sinha <anisinha@redhat.com>
@blackboxsw
Copy link
Collaborator

By safe, do you mean software security?

No what I mean is that there might be some inconsistency if ‘cloud-init init‘ doesn't recreate all the config files that were present before cleaning. The inconsistency might break cloud-init functionality.

@blackboxsw what do you think?

@ani-sinha thanks for the ping on this issue. I think the functionality of cloud-init clean is to provide a best effort to "reset" cloud-init to initial state so that cloud-init treats next boot of that image as a first initialization or "greenfield" boot. While the clean subcommand doesn't currently make an effort to remove any configuration artifacts produced by the previous run (such as user creation, ssh keys, ssh config, files written by write_files) I could see us trying to grow that optional functionality.
The reason I don't want cloud-init clean to purge any artifacts produced by various cc_*.py config modules is because I know of a few use-cases where individuals use two stage configuration to create reusable base images. They'll launch an image with cloud-init user-data in stage one to setup a common base image with base users,services package installs. I believe some packer installs also take this approach to creating a base image for reuse. Then that "cleaned" base image is uploaded to cloud/platform of choice and launched with new user-data to finalize configuration on vsphere or your favorite platform. If we grow cloud-init clean to be more 'destructive to previous config artifacts' let's make this optional/supplemental behavior and find a way to make it conspicuous.

@ani-sinha
Copy link
Contributor

By safe, do you mean software security?

No what I mean is that there might be some inconsistency if ‘cloud-init init‘ doesn't recreate all the config files that were present before cleaning. The inconsistency might break cloud-init functionality.

@blackboxsw what do you think?

@ani-sinha thanks for the ping on this issue. I think the functionality of cloud-init clean is to provide a best effort to "reset" cloud-init to initial state so that cloud-init treats next boot of that image as a first initialization or "greenfield" boot. While the clean subcommand doesn't currently make an effort to remove any configuration artifacts produced by the previous run (such as user creation, ssh keys, ssh config, files written by write_files) I could see us trying to grow that optional functionality. The reason I don't want cloud-init clean to purge any artifacts produced by various cc_*.py config modules is because I know of a few use-cases where individuals use two stage configuration to create reusable base images. They'll launch an image with cloud-init user-data in stage one to setup a common base image with base users,services package installs. I believe some packer installs also take this approach to creating a base image for reuse. Then that "cleaned" base image is uploaded to cloud/platform of choice and launched with new user-data to finalize configuration on vsphere or your favorite platform. If we grow cloud-init clean to be more 'destructive to previous config artifacts' let's make this optional/supplemental behavior and find a way to make it conspicuous.

OK I have added a new option under cloud-init clean which is optional. Also updated the documentation for the same which should make it conspicuous. See #4384 .

ani-sinha added a commit to ani-sinha/cloud-init that referenced this pull request Aug 29, 2023
cloud-init generates several config files today that are not cleaned as a part
of `cloud-init clean` operation. For example, cloud-init uses
`/etc/ssh/sshd_config.d/50-cloud-init.conf` to configure ssh daemon which is then
left uncleaned. This change adds a new option `cloud-init clean --configs` that
would clean up these config files as well. This new option provides two choices
- `ssh_config` and `network` that defines the scope of the config files that
would be cleaned - ssh configs or network configs. Additionally, the cli
documentation has also been updated to document this new option.

Reference:
canonical#1618

Fixes: canonicalGH-3240

Signed-off-by: Ani Sinha <anisinha@redhat.com>
ani-sinha added a commit to ani-sinha/cloud-init that referenced this pull request Aug 30, 2023
cloud-init generates several config files today that are not cleaned as a part
of `cloud-init clean` operation. For example, cloud-init uses
`/etc/ssh/sshd_config.d/50-cloud-init.conf` to configure ssh daemon which is then
left uncleaned. This change adds a new option `cloud-init clean --configs` that
would clean up these config files as well. This new option provides two choices
- `ssh_config` and `network` that defines the scope of the config files that
would be cleaned - ssh configs or network configs. They can be extended further
to include other types of config files as well in the future.
Additionally, the cli documentation has also been updated to document this
new option.

Reference:
canonical#1618

Fixes: canonicalGH-3240

Signed-off-by: Ani Sinha <anisinha@redhat.com>
ani-sinha added a commit to ani-sinha/cloud-init that referenced this pull request Aug 30, 2023
cloud-init generates several config files today that are not cleaned as a part
of `cloud-init clean` operation. For example, cloud-init uses
`/etc/ssh/sshd_config.d/50-cloud-init.conf` to configure ssh daemon which is then
left uncleaned. This change adds a new option `cloud-init clean --configs` that
would clean up these config files as well. This new option provides three
choices - `all`, `ssh_config` and `network` that defines the scope of the config
files that would be cleaned - ssh configs or network configs or all configs.
They can be extended further to include other types of config files as well in
the future. Additionally, the cli documentation has also been updated to
document this new option.

Reference:
canonical#1618

Fixes: canonicalGH-3240

Signed-off-by: Ani Sinha <anisinha@redhat.com>
Co-authored-by: Chad Smith <chad.smith@canonical.com>
ani-sinha added a commit to ani-sinha/cloud-init that referenced this pull request Aug 30, 2023
cloud-init generates several config files today that are not cleaned as a part
of `cloud-init clean` operation. For example, cloud-init uses
`/etc/ssh/sshd_config.d/50-cloud-init.conf` to configure ssh daemon which is then
left uncleaned. This change adds a new option `cloud-init clean --configs` that
would clean up these config files as well. This new option provides three
choices - `all`, `ssh_config` and `network` that defines the scope of the config
files that would be cleaned - ssh configs or network configs or all configs.
They can be extended further to include other types of config files as well in
the future. Additionally, the cli documentation has also been updated to
document this new option.

Reference:
canonical#1618

Fixes: canonicalGH-3240

Signed-off-by: Ani Sinha <anisinha@redhat.com>
Co-authored-by: Chad Smith <chad.smith@canonical.com>
ani-sinha added a commit to ani-sinha/cloud-init that referenced this pull request Aug 31, 2023
cloud-init generates several config files today that are not cleaned as a part
of `cloud-init clean` operation. For example, cloud-init uses
`/etc/ssh/sshd_config.d/50-cloud-init.conf` to configure ssh daemon which is then
left uncleaned. This change adds a new option `cloud-init clean --configs` that
would clean up these config files as well. This new option provides three
choices - `all`, `ssh_config` and `network` that defines the scope of the config
files that would be cleaned - ssh configs or network configs or all configs.
They can be extended further to include other types of config files as well in
the future. The cli documentation has also been updated to
document this new option. Additionally, this patch adds a new integration test
for the `clean` command.

Reference:
canonical#1618
Fixes: canonicalGH-3240

Signed-off-by: Ani Sinha <anisinha@redhat.com>
Co-authored-by: Chad Smith <chad.smith@canonical.com>
blackboxsw added a commit to ani-sinha/cloud-init that referenced this pull request Aug 31, 2023
cloud-init generates several config files today that are not cleaned as a part
of `cloud-init clean` operation. For example, cloud-init uses
`/etc/ssh/sshd_config.d/50-cloud-init.conf` to configure ssh daemon which is then
left uncleaned. This change adds a new option `cloud-init clean --configs` that
would clean up these config files as well. This new option provides three
choices - `all`, `ssh_config` and `network` that defines the scope of the config
files that would be cleaned - ssh configs or network configs or all configs.
They can be extended further to include other types of config files as well in
the future. The cli documentation has also been updated to
document this new option. Additionally, this patch adds a new integration test
for the `clean` command.

Reference:
canonical#1618
Fixes: canonicalGH-3240

Signed-off-by: Ani Sinha <anisinha@redhat.com>
Co-authored-by: Chad Smith <chad.smith@canonical.com>
blackboxsw added a commit that referenced this pull request Aug 31, 2023
cloud-init generates several config files today that are not cleaned as a part
of `cloud-init clean` operation. For example, cloud-init uses
`/etc/ssh/sshd_config.d/50-cloud-init.conf` to configure ssh daemon which is then
left uncleaned. This change adds a new option `cloud-init clean --configs` that
would clean up these config files as well. This new option provides three
choices - `all`, `ssh_config` and `network` that defines the scope of the config
files that would be cleaned - ssh configs or network configs or all configs.
They can be extended further to include other types of config files as well in
the future. The cli documentation has also been updated to
document this new option. Additionally, this patch adds a new integration test
for the `clean` command.

Reference:
#1618

Fixes GH-3240

Signed-off-by: Ani Sinha <anisinha@redhat.com>
Co-authored-by: Chad Smith <chad.smith@canonical.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants