forked from rpms/cloud-init
import cloud-init-21.1-7.el9
This commit is contained in:
commit
471cc202a7
1
.cloud-init.metadata
Normal file
1
.cloud-init.metadata
Normal file
@ -0,0 +1 @@
|
|||||||
|
2ae378aa2ae23b34b0ff123623ba5e2fbdc4928d SOURCES/cloud-init-21.1.tar.gz
|
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
SOURCES/cloud-init-21.1.tar.gz
|
604
SOURCES/0001-Add-initial-redhat-setup.patch
Normal file
604
SOURCES/0001-Add-initial-redhat-setup.patch
Normal file
@ -0,0 +1,604 @@
|
|||||||
|
From 4b84d29211b7b2121afe9045c71ded5381536d8b Mon Sep 17 00:00:00 2001
|
||||||
|
From: Eduardo Otubo <otubo@redhat.com>
|
||||||
|
Date: Fri, 7 May 2021 13:36:03 +0200
|
||||||
|
Subject: Add initial redhat setup
|
||||||
|
|
||||||
|
Merged patches (RHEL-9/21.1):
|
||||||
|
- 5688a1d0 Removing python-nose and python-tox as dependency
|
||||||
|
- 237d57f9 Removing mock dependency
|
||||||
|
- d1c2f496 Removing python-jsonschema dependency
|
||||||
|
- 0d1cd14c Don't override default network configuration
|
||||||
|
|
||||||
|
Merged patches (21.1):
|
||||||
|
- 915d30ad Change gating file to correct rhel version
|
||||||
|
- 311f318d Removing net-tools dependency
|
||||||
|
- 74731806 Adding man pages to Red Hat spec file
|
||||||
|
- 758d333d Removing blocking test from yaml configuration file
|
||||||
|
- c7e7c59c Changing permission of cloud-init-generator to 755
|
||||||
|
- 8b85abbb Installing man pages in the correct place with correct permissions
|
||||||
|
- c6808d8d Fix unit failure of cloud-final.service if NetworkManager was not present.
|
||||||
|
- 11866ef6 Report full specific version with "cloud-init --version"
|
||||||
|
|
||||||
|
Rebase notes (18.5):
|
||||||
|
- added bash_completition file
|
||||||
|
- added cloud-id file
|
||||||
|
|
||||||
|
Merged patches (20.3):
|
||||||
|
- 01900d0 changing ds-identify patch from /usr/lib to /usr/libexec
|
||||||
|
- 7f47ca3 Render the generator from template instead of cp
|
||||||
|
|
||||||
|
Merged patches (19.4):
|
||||||
|
- 4ab5a61 Fix for network configuration not persisting after reboot
|
||||||
|
- 84cf125 Removing cloud-user from wheel
|
||||||
|
- 31290ab Adding gating tests for Azure, ESXi and AWS
|
||||||
|
|
||||||
|
Merged patches (18.5):
|
||||||
|
- 2d6b469 add power-state-change module to cloud_final_modules
|
||||||
|
- 764159f Adding systemd mount options to wait for cloud-init
|
||||||
|
- da4d99e Adding disk_setup to rhel/cloud.cfg
|
||||||
|
- f5c6832 Enable cloud-init by default on vmware
|
||||||
|
|
||||||
|
Conflicts:
|
||||||
|
cloudinit/config/cc_chef.py:
|
||||||
|
- Updated header documentation text
|
||||||
|
- Replacing double quotes by simple quotes
|
||||||
|
|
||||||
|
setup.py:
|
||||||
|
- Adding missing cmdclass info
|
||||||
|
|
||||||
|
Signed-off-by: Eduardo Otubo <otubo@redhat.com>
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
- move redhat to .distro to use new build script structure
|
||||||
|
- Fixing changelog for RHEL 9
|
||||||
|
|
||||||
|
Merged patches (21.1):
|
||||||
|
- 69bd7f71 DataSourceAzure.py: use hostnamectl to set hostname
|
||||||
|
- 0407867e Remove race condition between cloud-init and NetworkManager
|
||||||
|
|
||||||
|
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||||
|
---
|
||||||
|
.distro/.gitignore | 1 +
|
||||||
|
.distro/Makefile | 74 +++++
|
||||||
|
.distro/Makefile.common | 30 ++
|
||||||
|
.distro/cloud-init-tmpfiles.conf | 1 +
|
||||||
|
.distro/cloud-init.spec.template | 383 ++++++++++++++++++++++++++
|
||||||
|
.distro/gating.yaml | 8 +
|
||||||
|
.distro/rpmbuild/BUILD/.gitignore | 3 +
|
||||||
|
.distro/rpmbuild/RPMS/.gitignore | 3 +
|
||||||
|
.distro/rpmbuild/SOURCES/.gitignore | 3 +
|
||||||
|
.distro/rpmbuild/SPECS/.gitignore | 3 +
|
||||||
|
.distro/rpmbuild/SRPMS/.gitignore | 3 +
|
||||||
|
.distro/scripts/frh.py | 27 ++
|
||||||
|
.distro/scripts/git-backport-diff | 327 ++++++++++++++++++++++
|
||||||
|
.distro/scripts/git-compile-check | 215 +++++++++++++++
|
||||||
|
.distro/scripts/process-patches.sh | 88 ++++++
|
||||||
|
.distro/scripts/tarball_checksum.sh | 3 +
|
||||||
|
.gitignore | 1 +
|
||||||
|
cloudinit/config/cc_chef.py | 67 ++++-
|
||||||
|
cloudinit/settings.py | 7 +-
|
||||||
|
cloudinit/sources/DataSourceAzure.py | 2 +-
|
||||||
|
requirements.txt | 3 -
|
||||||
|
rhel/README.rhel | 5 +
|
||||||
|
rhel/cloud-init-tmpfiles.conf | 1 +
|
||||||
|
rhel/cloud.cfg | 69 +++++
|
||||||
|
rhel/systemd/cloud-config.service | 18 ++
|
||||||
|
rhel/systemd/cloud-config.target | 11 +
|
||||||
|
rhel/systemd/cloud-final.service | 24 ++
|
||||||
|
rhel/systemd/cloud-init-local.service | 31 +++
|
||||||
|
rhel/systemd/cloud-init.service | 26 ++
|
||||||
|
rhel/systemd/cloud-init.target | 7 +
|
||||||
|
setup.py | 23 +-
|
||||||
|
tools/read-version | 28 +-
|
||||||
|
32 files changed, 1441 insertions(+), 54 deletions(-)
|
||||||
|
create mode 100644 .distro/.gitignore
|
||||||
|
create mode 100644 .distro/Makefile
|
||||||
|
create mode 100644 .distro/Makefile.common
|
||||||
|
create mode 100644 .distro/cloud-init-tmpfiles.conf
|
||||||
|
create mode 100644 .distro/cloud-init.spec.template
|
||||||
|
create mode 100644 .distro/gating.yaml
|
||||||
|
create mode 100644 .distro/rpmbuild/BUILD/.gitignore
|
||||||
|
create mode 100644 .distro/rpmbuild/RPMS/.gitignore
|
||||||
|
create mode 100644 .distro/rpmbuild/SOURCES/.gitignore
|
||||||
|
create mode 100644 .distro/rpmbuild/SPECS/.gitignore
|
||||||
|
create mode 100644 .distro/rpmbuild/SRPMS/.gitignore
|
||||||
|
create mode 100755 .distro/scripts/frh.py
|
||||||
|
create mode 100755 .distro/scripts/git-backport-diff
|
||||||
|
create mode 100755 .distro/scripts/git-compile-check
|
||||||
|
create mode 100755 .distro/scripts/process-patches.sh
|
||||||
|
create mode 100755 .distro/scripts/tarball_checksum.sh
|
||||||
|
create mode 100644 rhel/README.rhel
|
||||||
|
create mode 100644 rhel/cloud-init-tmpfiles.conf
|
||||||
|
create mode 100644 rhel/cloud.cfg
|
||||||
|
create mode 100644 rhel/systemd/cloud-config.service
|
||||||
|
create mode 100644 rhel/systemd/cloud-config.target
|
||||||
|
create mode 100644 rhel/systemd/cloud-final.service
|
||||||
|
create mode 100644 rhel/systemd/cloud-init-local.service
|
||||||
|
create mode 100644 rhel/systemd/cloud-init.service
|
||||||
|
create mode 100644 rhel/systemd/cloud-init.target
|
||||||
|
|
||||||
|
diff --git a/cloudinit/config/cc_chef.py b/cloudinit/config/cc_chef.py
|
||||||
|
index aaf71366..97ef649a 100644
|
||||||
|
--- a/cloudinit/config/cc_chef.py
|
||||||
|
+++ b/cloudinit/config/cc_chef.py
|
||||||
|
@@ -6,7 +6,70 @@
|
||||||
|
#
|
||||||
|
# This file is part of cloud-init. See LICENSE file for license information.
|
||||||
|
|
||||||
|
-"""Chef: module that configures, starts and installs chef."""
|
||||||
|
+"""
|
||||||
|
+Chef
|
||||||
|
+----
|
||||||
|
+**Summary:** module that configures, starts and installs chef.
|
||||||
|
+
|
||||||
|
+This module enables chef to be installed (from packages or
|
||||||
|
+from gems, or from omnibus). Before this occurs chef configurations are
|
||||||
|
+written to disk (validation.pem, client.pem, firstboot.json, client.rb),
|
||||||
|
+and needed chef folders/directories are created (/etc/chef and /var/log/chef
|
||||||
|
+and so-on). Then once installing proceeds correctly if configured chef will
|
||||||
|
+be started (in daemon mode or in non-daemon mode) and then once that has
|
||||||
|
+finished (if ran in non-daemon mode this will be when chef finishes
|
||||||
|
+converging, if ran in daemon mode then no further actions are possible since
|
||||||
|
+chef will have forked into its own process) then a post run function can
|
||||||
|
+run that can do finishing activities (such as removing the validation pem
|
||||||
|
+file).
|
||||||
|
+
|
||||||
|
+**Internal name:** ``cc_chef``
|
||||||
|
+
|
||||||
|
+**Module frequency:** per always
|
||||||
|
+
|
||||||
|
+**Supported distros:** all
|
||||||
|
+
|
||||||
|
+**Config keys**::
|
||||||
|
+
|
||||||
|
+ chef:
|
||||||
|
+ directories: (defaulting to /etc/chef, /var/log/chef, /var/lib/chef,
|
||||||
|
+ /var/cache/chef, /var/backups/chef, /run/chef)
|
||||||
|
+ validation_cert: (optional string to be written to file validation_key)
|
||||||
|
+ special value 'system' means set use existing file
|
||||||
|
+ validation_key: (optional the path for validation_cert. default
|
||||||
|
+ /etc/chef/validation.pem)
|
||||||
|
+ firstboot_path: (path to write run_list and initial_attributes keys that
|
||||||
|
+ should also be present in this configuration, defaults
|
||||||
|
+ to /etc/chef/firstboot.json)
|
||||||
|
+ exec: boolean to run or not run chef (defaults to false, unless
|
||||||
|
+ a gem installed is requested
|
||||||
|
+ where this will then default
|
||||||
|
+ to true)
|
||||||
|
+
|
||||||
|
+ chef.rb template keys (if falsey, then will be skipped and not
|
||||||
|
+ written to /etc/chef/client.rb)
|
||||||
|
+
|
||||||
|
+ chef:
|
||||||
|
+ client_key:
|
||||||
|
+ encrypted_data_bag_secret:
|
||||||
|
+ environment:
|
||||||
|
+ file_backup_path:
|
||||||
|
+ file_cache_path:
|
||||||
|
+ json_attribs:
|
||||||
|
+ log_level:
|
||||||
|
+ log_location:
|
||||||
|
+ node_name:
|
||||||
|
+ omnibus_url:
|
||||||
|
+ omnibus_url_retries:
|
||||||
|
+ omnibus_version:
|
||||||
|
+ pid_file:
|
||||||
|
+ server_url:
|
||||||
|
+ show_time:
|
||||||
|
+ ssl_verify_mode:
|
||||||
|
+ validation_cert:
|
||||||
|
+ validation_key:
|
||||||
|
+ validation_name:
|
||||||
|
+"""
|
||||||
|
|
||||||
|
import itertools
|
||||||
|
import json
|
||||||
|
@@ -31,7 +94,7 @@ CHEF_DIRS = tuple([
|
||||||
|
'/var/lib/chef',
|
||||||
|
'/var/cache/chef',
|
||||||
|
'/var/backups/chef',
|
||||||
|
- '/var/run/chef',
|
||||||
|
+ '/run/chef',
|
||||||
|
])
|
||||||
|
REQUIRED_CHEF_DIRS = tuple([
|
||||||
|
'/etc/chef',
|
||||||
|
diff --git a/cloudinit/settings.py b/cloudinit/settings.py
|
||||||
|
index 91e1bfe7..e690c0fd 100644
|
||||||
|
--- a/cloudinit/settings.py
|
||||||
|
+++ b/cloudinit/settings.py
|
||||||
|
@@ -47,13 +47,16 @@ CFG_BUILTIN = {
|
||||||
|
],
|
||||||
|
'def_log_file': '/var/log/cloud-init.log',
|
||||||
|
'log_cfgs': [],
|
||||||
|
- 'syslog_fix_perms': ['syslog:adm', 'root:adm', 'root:wheel', 'root:root'],
|
||||||
|
+ 'mount_default_fields': [None, None, 'auto', 'defaults,nofail', '0', '2'],
|
||||||
|
+ 'ssh_deletekeys': False,
|
||||||
|
+ 'ssh_genkeytypes': [],
|
||||||
|
+ 'syslog_fix_perms': [],
|
||||||
|
'system_info': {
|
||||||
|
'paths': {
|
||||||
|
'cloud_dir': '/var/lib/cloud',
|
||||||
|
'templates_dir': '/etc/cloud/templates/',
|
||||||
|
},
|
||||||
|
- 'distro': 'ubuntu',
|
||||||
|
+ 'distro': 'rhel',
|
||||||
|
'network': {'renderers': None},
|
||||||
|
},
|
||||||
|
'vendor_data': {'enabled': True, 'prefix': []},
|
||||||
|
diff --git a/cloudinit/sources/DataSourceAzure.py b/cloudinit/sources/DataSourceAzure.py
|
||||||
|
index cee630f7..553b5a7e 100755
|
||||||
|
--- a/cloudinit/sources/DataSourceAzure.py
|
||||||
|
+++ b/cloudinit/sources/DataSourceAzure.py
|
||||||
|
@@ -296,7 +296,7 @@ def get_hostname(hostname_command='hostname'):
|
||||||
|
|
||||||
|
|
||||||
|
def set_hostname(hostname, hostname_command='hostname'):
|
||||||
|
- subp.subp([hostname_command, hostname])
|
||||||
|
+ util.subp(['hostnamectl', 'set-hostname', str(hostname)])
|
||||||
|
|
||||||
|
|
||||||
|
@azure_ds_telemetry_reporter
|
||||||
|
diff --git a/requirements.txt b/requirements.txt
|
||||||
|
index 5817da3b..5b8becd7 100644
|
||||||
|
--- a/requirements.txt
|
||||||
|
+++ b/requirements.txt
|
||||||
|
@@ -29,6 +29,3 @@ requests
|
||||||
|
|
||||||
|
# For patching pieces of cloud-config together
|
||||||
|
jsonpatch
|
||||||
|
-
|
||||||
|
-# For validating cloud-config sections per schema definitions
|
||||||
|
-jsonschema
|
||||||
|
diff --git a/rhel/README.rhel b/rhel/README.rhel
|
||||||
|
new file mode 100644
|
||||||
|
index 00000000..aa29630d
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/rhel/README.rhel
|
||||||
|
@@ -0,0 +1,5 @@
|
||||||
|
+The following cloud-init modules are currently unsupported on this OS:
|
||||||
|
+ - apt_update_upgrade ('apt_update', 'apt_upgrade', 'apt_mirror', 'apt_preserve_sources_list', 'apt_old_mirror', 'apt_sources', 'debconf_selections', 'packages' options)
|
||||||
|
+ - byobu ('byobu_by_default' option)
|
||||||
|
+ - chef
|
||||||
|
+ - grub_dpkg
|
||||||
|
diff --git a/rhel/cloud-init-tmpfiles.conf b/rhel/cloud-init-tmpfiles.conf
|
||||||
|
new file mode 100644
|
||||||
|
index 00000000..0c6d2a3b
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/rhel/cloud-init-tmpfiles.conf
|
||||||
|
@@ -0,0 +1 @@
|
||||||
|
+d /run/cloud-init 0700 root root - -
|
||||||
|
diff --git a/rhel/cloud.cfg b/rhel/cloud.cfg
|
||||||
|
new file mode 100644
|
||||||
|
index 00000000..9ecba215
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/rhel/cloud.cfg
|
||||||
|
@@ -0,0 +1,69 @@
|
||||||
|
+users:
|
||||||
|
+ - default
|
||||||
|
+
|
||||||
|
+disable_root: 1
|
||||||
|
+ssh_pwauth: 0
|
||||||
|
+
|
||||||
|
+mount_default_fields: [~, ~, 'auto', 'defaults,nofail,x-systemd.requires=cloud-init.service', '0', '2']
|
||||||
|
+resize_rootfs_tmp: /dev
|
||||||
|
+ssh_deletekeys: 1
|
||||||
|
+ssh_genkeytypes: ~
|
||||||
|
+syslog_fix_perms: ~
|
||||||
|
+disable_vmware_customization: false
|
||||||
|
+
|
||||||
|
+cloud_init_modules:
|
||||||
|
+ - disk_setup
|
||||||
|
+ - migrator
|
||||||
|
+ - bootcmd
|
||||||
|
+ - write-files
|
||||||
|
+ - growpart
|
||||||
|
+ - resizefs
|
||||||
|
+ - set_hostname
|
||||||
|
+ - update_hostname
|
||||||
|
+ - update_etc_hosts
|
||||||
|
+ - rsyslog
|
||||||
|
+ - users-groups
|
||||||
|
+ - ssh
|
||||||
|
+
|
||||||
|
+cloud_config_modules:
|
||||||
|
+ - mounts
|
||||||
|
+ - locale
|
||||||
|
+ - set-passwords
|
||||||
|
+ - rh_subscription
|
||||||
|
+ - yum-add-repo
|
||||||
|
+ - package-update-upgrade-install
|
||||||
|
+ - timezone
|
||||||
|
+ - puppet
|
||||||
|
+ - chef
|
||||||
|
+ - salt-minion
|
||||||
|
+ - mcollective
|
||||||
|
+ - disable-ec2-metadata
|
||||||
|
+ - runcmd
|
||||||
|
+
|
||||||
|
+cloud_final_modules:
|
||||||
|
+ - rightscale_userdata
|
||||||
|
+ - scripts-per-once
|
||||||
|
+ - scripts-per-boot
|
||||||
|
+ - scripts-per-instance
|
||||||
|
+ - scripts-user
|
||||||
|
+ - ssh-authkey-fingerprints
|
||||||
|
+ - keys-to-console
|
||||||
|
+ - phone-home
|
||||||
|
+ - final-message
|
||||||
|
+ - power-state-change
|
||||||
|
+
|
||||||
|
+system_info:
|
||||||
|
+ default_user:
|
||||||
|
+ name: cloud-user
|
||||||
|
+ lock_passwd: true
|
||||||
|
+ gecos: Cloud User
|
||||||
|
+ groups: [adm, systemd-journal]
|
||||||
|
+ sudo: ["ALL=(ALL) NOPASSWD:ALL"]
|
||||||
|
+ shell: /bin/bash
|
||||||
|
+ distro: rhel
|
||||||
|
+ paths:
|
||||||
|
+ cloud_dir: /var/lib/cloud
|
||||||
|
+ templates_dir: /etc/cloud/templates
|
||||||
|
+ ssh_svcname: sshd
|
||||||
|
+
|
||||||
|
+# vim:syntax=yaml
|
||||||
|
diff --git a/rhel/systemd/cloud-config.service b/rhel/systemd/cloud-config.service
|
||||||
|
new file mode 100644
|
||||||
|
index 00000000..f3dcd4be
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/rhel/systemd/cloud-config.service
|
||||||
|
@@ -0,0 +1,18 @@
|
||||||
|
+[Unit]
|
||||||
|
+Description=Apply the settings specified in cloud-config
|
||||||
|
+After=network-online.target cloud-config.target
|
||||||
|
+Wants=network-online.target cloud-config.target
|
||||||
|
+ConditionPathExists=!/etc/cloud/cloud-init.disabled
|
||||||
|
+ConditionKernelCommandLine=!cloud-init=disabled
|
||||||
|
+
|
||||||
|
+[Service]
|
||||||
|
+Type=oneshot
|
||||||
|
+ExecStart=/usr/bin/cloud-init modules --mode=config
|
||||||
|
+RemainAfterExit=yes
|
||||||
|
+TimeoutSec=0
|
||||||
|
+
|
||||||
|
+# Output needs to appear in instance console output
|
||||||
|
+StandardOutput=journal+console
|
||||||
|
+
|
||||||
|
+[Install]
|
||||||
|
+WantedBy=cloud-init.target
|
||||||
|
diff --git a/rhel/systemd/cloud-config.target b/rhel/systemd/cloud-config.target
|
||||||
|
new file mode 100644
|
||||||
|
index 00000000..ae9b7d02
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/rhel/systemd/cloud-config.target
|
||||||
|
@@ -0,0 +1,11 @@
|
||||||
|
+# cloud-init normally emits a "cloud-config" upstart event to inform third
|
||||||
|
+# parties that cloud-config is available, which does us no good when we're
|
||||||
|
+# using systemd. cloud-config.target serves as this synchronization point
|
||||||
|
+# instead. Services that would "start on cloud-config" with upstart can
|
||||||
|
+# instead use "After=cloud-config.target" and "Wants=cloud-config.target"
|
||||||
|
+# as appropriate.
|
||||||
|
+
|
||||||
|
+[Unit]
|
||||||
|
+Description=Cloud-config availability
|
||||||
|
+Wants=cloud-init-local.service cloud-init.service
|
||||||
|
+After=cloud-init-local.service cloud-init.service
|
||||||
|
diff --git a/rhel/systemd/cloud-final.service b/rhel/systemd/cloud-final.service
|
||||||
|
new file mode 100644
|
||||||
|
index 00000000..e281c0cf
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/rhel/systemd/cloud-final.service
|
||||||
|
@@ -0,0 +1,24 @@
|
||||||
|
+[Unit]
|
||||||
|
+Description=Execute cloud user/final scripts
|
||||||
|
+After=network-online.target cloud-config.service rc-local.service
|
||||||
|
+Wants=network-online.target cloud-config.service
|
||||||
|
+ConditionPathExists=!/etc/cloud/cloud-init.disabled
|
||||||
|
+ConditionKernelCommandLine=!cloud-init=disabled
|
||||||
|
+
|
||||||
|
+[Service]
|
||||||
|
+Type=oneshot
|
||||||
|
+ExecStart=/usr/bin/cloud-init modules --mode=final
|
||||||
|
+RemainAfterExit=yes
|
||||||
|
+TimeoutSec=0
|
||||||
|
+KillMode=process
|
||||||
|
+# Restart NetworkManager if it is present and running.
|
||||||
|
+ExecStartPost=/bin/sh -c 'u=NetworkManager.service; \
|
||||||
|
+ out=$(systemctl show --property=SubState $u) || exit; \
|
||||||
|
+ [ "$out" = "SubState=running" ] || exit 0; \
|
||||||
|
+ systemctl reload-or-try-restart $u'
|
||||||
|
+
|
||||||
|
+# Output needs to appear in instance console output
|
||||||
|
+StandardOutput=journal+console
|
||||||
|
+
|
||||||
|
+[Install]
|
||||||
|
+WantedBy=cloud-init.target
|
||||||
|
diff --git a/rhel/systemd/cloud-init-local.service b/rhel/systemd/cloud-init-local.service
|
||||||
|
new file mode 100644
|
||||||
|
index 00000000..8f9f6c9f
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/rhel/systemd/cloud-init-local.service
|
||||||
|
@@ -0,0 +1,31 @@
|
||||||
|
+[Unit]
|
||||||
|
+Description=Initial cloud-init job (pre-networking)
|
||||||
|
+DefaultDependencies=no
|
||||||
|
+Wants=network-pre.target
|
||||||
|
+After=systemd-remount-fs.service
|
||||||
|
+Requires=dbus.socket
|
||||||
|
+After=dbus.socket
|
||||||
|
+Before=NetworkManager.service network.service
|
||||||
|
+Before=network-pre.target
|
||||||
|
+Before=shutdown.target
|
||||||
|
+Before=firewalld.target
|
||||||
|
+Conflicts=shutdown.target
|
||||||
|
+RequiresMountsFor=/var/lib/cloud
|
||||||
|
+ConditionPathExists=!/etc/cloud/cloud-init.disabled
|
||||||
|
+ConditionKernelCommandLine=!cloud-init=disabled
|
||||||
|
+
|
||||||
|
+[Service]
|
||||||
|
+Type=oneshot
|
||||||
|
+ExecStartPre=/bin/mkdir -p /run/cloud-init
|
||||||
|
+ExecStartPre=/sbin/restorecon /run/cloud-init
|
||||||
|
+ExecStartPre=/usr/bin/touch /run/cloud-init/enabled
|
||||||
|
+ExecStart=/usr/bin/cloud-init init --local
|
||||||
|
+ExecStart=/bin/touch /run/cloud-init/network-config-ready
|
||||||
|
+RemainAfterExit=yes
|
||||||
|
+TimeoutSec=0
|
||||||
|
+
|
||||||
|
+# Output needs to appear in instance console output
|
||||||
|
+StandardOutput=journal+console
|
||||||
|
+
|
||||||
|
+[Install]
|
||||||
|
+WantedBy=cloud-init.target
|
||||||
|
diff --git a/rhel/systemd/cloud-init.service b/rhel/systemd/cloud-init.service
|
||||||
|
new file mode 100644
|
||||||
|
index 00000000..0b3d796d
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/rhel/systemd/cloud-init.service
|
||||||
|
@@ -0,0 +1,26 @@
|
||||||
|
+[Unit]
|
||||||
|
+Description=Initial cloud-init job (metadata service crawler)
|
||||||
|
+Wants=cloud-init-local.service
|
||||||
|
+Wants=sshd-keygen.service
|
||||||
|
+Wants=sshd.service
|
||||||
|
+After=cloud-init-local.service
|
||||||
|
+After=NetworkManager.service network.service
|
||||||
|
+After=NetworkManager-wait-online.service
|
||||||
|
+Before=network-online.target
|
||||||
|
+Before=sshd-keygen.service
|
||||||
|
+Before=sshd.service
|
||||||
|
+Before=systemd-user-sessions.service
|
||||||
|
+ConditionPathExists=!/etc/cloud/cloud-init.disabled
|
||||||
|
+ConditionKernelCommandLine=!cloud-init=disabled
|
||||||
|
+
|
||||||
|
+[Service]
|
||||||
|
+Type=oneshot
|
||||||
|
+ExecStart=/usr/bin/cloud-init init
|
||||||
|
+RemainAfterExit=yes
|
||||||
|
+TimeoutSec=0
|
||||||
|
+
|
||||||
|
+# Output needs to appear in instance console output
|
||||||
|
+StandardOutput=journal+console
|
||||||
|
+
|
||||||
|
+[Install]
|
||||||
|
+WantedBy=cloud-init.target
|
||||||
|
diff --git a/rhel/systemd/cloud-init.target b/rhel/systemd/cloud-init.target
|
||||||
|
new file mode 100644
|
||||||
|
index 00000000..083c3b6f
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/rhel/systemd/cloud-init.target
|
||||||
|
@@ -0,0 +1,7 @@
|
||||||
|
+# cloud-init target is enabled by cloud-init-generator
|
||||||
|
+# To disable it you can either:
|
||||||
|
+# a.) boot with kernel cmdline of 'cloud-init=disabled'
|
||||||
|
+# b.) touch a file /etc/cloud/cloud-init.disabled
|
||||||
|
+[Unit]
|
||||||
|
+Description=Cloud-init target
|
||||||
|
+After=multi-user.target
|
||||||
|
diff --git a/setup.py b/setup.py
|
||||||
|
index cbacf48e..d5cd01a4 100755
|
||||||
|
--- a/setup.py
|
||||||
|
+++ b/setup.py
|
||||||
|
@@ -125,14 +125,6 @@ INITSYS_FILES = {
|
||||||
|
'sysvinit_deb': [f for f in glob('sysvinit/debian/*') if is_f(f)],
|
||||||
|
'sysvinit_openrc': [f for f in glob('sysvinit/gentoo/*') if is_f(f)],
|
||||||
|
'sysvinit_suse': [f for f in glob('sysvinit/suse/*') if is_f(f)],
|
||||||
|
- 'systemd': [render_tmpl(f)
|
||||||
|
- for f in (glob('systemd/*.tmpl') +
|
||||||
|
- glob('systemd/*.service') +
|
||||||
|
- glob('systemd/*.target'))
|
||||||
|
- if (is_f(f) and not is_generator(f))],
|
||||||
|
- 'systemd.generators': [
|
||||||
|
- render_tmpl(f, mode=0o755)
|
||||||
|
- for f in glob('systemd/*') if is_f(f) and is_generator(f)],
|
||||||
|
'upstart': [f for f in glob('upstart/*') if is_f(f)],
|
||||||
|
}
|
||||||
|
INITSYS_ROOTS = {
|
||||||
|
@@ -142,9 +134,6 @@ INITSYS_ROOTS = {
|
||||||
|
'sysvinit_deb': 'etc/init.d',
|
||||||
|
'sysvinit_openrc': 'etc/init.d',
|
||||||
|
'sysvinit_suse': 'etc/init.d',
|
||||||
|
- 'systemd': pkg_config_read('systemd', 'systemdsystemunitdir'),
|
||||||
|
- 'systemd.generators': pkg_config_read('systemd',
|
||||||
|
- 'systemdsystemgeneratordir'),
|
||||||
|
'upstart': 'etc/init/',
|
||||||
|
}
|
||||||
|
INITSYS_TYPES = sorted([f.partition(".")[0] for f in INITSYS_ROOTS.keys()])
|
||||||
|
@@ -245,14 +234,11 @@ if not in_virtualenv():
|
||||||
|
INITSYS_ROOTS[k] = "/" + INITSYS_ROOTS[k]
|
||||||
|
|
||||||
|
data_files = [
|
||||||
|
- (ETC + '/cloud', [render_tmpl("config/cloud.cfg.tmpl")]),
|
||||||
|
+ (ETC + '/bash_completion.d', ['bash_completion/cloud-init']),
|
||||||
|
(ETC + '/cloud/cloud.cfg.d', glob('config/cloud.cfg.d/*')),
|
||||||
|
(ETC + '/cloud/templates', glob('templates/*')),
|
||||||
|
- (USR_LIB_EXEC + '/cloud-init', ['tools/ds-identify',
|
||||||
|
- 'tools/uncloud-init',
|
||||||
|
+ (USR_LIB_EXEC + '/cloud-init', ['tools/uncloud-init',
|
||||||
|
'tools/write-ssh-key-fingerprints']),
|
||||||
|
- (USR + '/share/bash-completion/completions',
|
||||||
|
- ['bash_completion/cloud-init']),
|
||||||
|
(USR + '/share/doc/cloud-init', [f for f in glob('doc/*') if is_f(f)]),
|
||||||
|
(USR + '/share/doc/cloud-init/examples',
|
||||||
|
[f for f in glob('doc/examples/*') if is_f(f)]),
|
||||||
|
@@ -263,8 +249,7 @@ if not platform.system().endswith('BSD'):
|
||||||
|
data_files.extend([
|
||||||
|
(ETC + '/NetworkManager/dispatcher.d/',
|
||||||
|
['tools/hook-network-manager']),
|
||||||
|
- (ETC + '/dhcp/dhclient-exit-hooks.d/', ['tools/hook-dhclient']),
|
||||||
|
- (LIB + '/udev/rules.d', [f for f in glob('udev/*.rules')])
|
||||||
|
+ ('/usr/lib/udev/rules.d', [f for f in glob('udev/*.rules')])
|
||||||
|
])
|
||||||
|
# Use a subclass for install that handles
|
||||||
|
# adding on the right init system configuration files
|
||||||
|
@@ -286,8 +271,6 @@ setuptools.setup(
|
||||||
|
scripts=['tools/cloud-init-per'],
|
||||||
|
license='Dual-licensed under GPLv3 or Apache 2.0',
|
||||||
|
data_files=data_files,
|
||||||
|
- install_requires=requirements,
|
||||||
|
- cmdclass=cmdclass,
|
||||||
|
entry_points={
|
||||||
|
'console_scripts': [
|
||||||
|
'cloud-init = cloudinit.cmd.main:main',
|
||||||
|
diff --git a/tools/read-version b/tools/read-version
|
||||||
|
index 02c90643..79755f78 100755
|
||||||
|
--- a/tools/read-version
|
||||||
|
+++ b/tools/read-version
|
||||||
|
@@ -71,32 +71,8 @@ version_long = None
|
||||||
|
is_release_branch_ci = (
|
||||||
|
os.environ.get("TRAVIS_PULL_REQUEST_BRANCH", "").startswith("upstream/")
|
||||||
|
)
|
||||||
|
-if is_gitdir(_tdir) and which("git") and not is_release_branch_ci:
|
||||||
|
- flags = []
|
||||||
|
- if use_tags:
|
||||||
|
- flags = ['--tags']
|
||||||
|
- cmd = ['git', 'describe', '--abbrev=8', '--match=[0-9]*'] + flags
|
||||||
|
-
|
||||||
|
- try:
|
||||||
|
- version = tiny_p(cmd).strip()
|
||||||
|
- except RuntimeError:
|
||||||
|
- version = None
|
||||||
|
-
|
||||||
|
- if version is None or not version.startswith(src_version):
|
||||||
|
- sys.stderr.write("git describe version (%s) differs from "
|
||||||
|
- "cloudinit.version (%s)\n" % (version, src_version))
|
||||||
|
- sys.stderr.write(
|
||||||
|
- "Please get the latest upstream tags.\n"
|
||||||
|
- "As an example, this can be done with the following:\n"
|
||||||
|
- "$ git remote add upstream https://git.launchpad.net/cloud-init\n"
|
||||||
|
- "$ git fetch upstream --tags\n"
|
||||||
|
- )
|
||||||
|
- sys.exit(1)
|
||||||
|
-
|
||||||
|
- version_long = tiny_p(cmd + ["--long"]).strip()
|
||||||
|
-else:
|
||||||
|
- version = src_version
|
||||||
|
- version_long = None
|
||||||
|
+version = src_version
|
||||||
|
+version_long = None
|
||||||
|
|
||||||
|
# version is X.Y.Z[+xxx.gHASH]
|
||||||
|
# version_long is None or X.Y.Z-xxx-gHASH
|
||||||
|
--
|
||||||
|
2.27.0
|
||||||
|
|
@ -0,0 +1,283 @@
|
|||||||
|
From 3f895d7236fab4f12482435829b530022a2205ec Mon Sep 17 00:00:00 2001
|
||||||
|
From: Eduardo Otubo <otubo@redhat.com>
|
||||||
|
Date: Fri, 7 May 2021 13:36:06 +0200
|
||||||
|
Subject: Do not write NM_CONTROLLED=no in generated interface config files
|
||||||
|
|
||||||
|
Conflicts 20.3:
|
||||||
|
- Not appplying patch on cloudinit/net/sysconfig.py since it now has a
|
||||||
|
mechanism to identify if cloud-init is running on RHEL, having the
|
||||||
|
correct settings for NM_CONTROLLED.
|
||||||
|
|
||||||
|
Merged patches (21.1):
|
||||||
|
- ecbace48 sysconfig: Don't write BOOTPROTO=dhcp for ipv6 dhcp
|
||||||
|
- a1a00383 include 'NOZEROCONF=yes' in /etc/sysconfig/network
|
||||||
|
X-downstream-only: true
|
||||||
|
Signed-off-by: Eduardo Otubo <otubo@redhat.com>
|
||||||
|
Signed-off-by: Ryan McCabe <rmccabe@redhat.com>
|
||||||
|
---
|
||||||
|
cloudinit/net/sysconfig.py | 13 +++++++++++--
|
||||||
|
tests/unittests/test_net.py | 28 ----------------------------
|
||||||
|
2 files changed, 11 insertions(+), 30 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/cloudinit/net/sysconfig.py b/cloudinit/net/sysconfig.py
|
||||||
|
index 99a4bae4..d5440998 100644
|
||||||
|
--- a/cloudinit/net/sysconfig.py
|
||||||
|
+++ b/cloudinit/net/sysconfig.py
|
||||||
|
@@ -289,7 +289,7 @@ class Renderer(renderer.Renderer):
|
||||||
|
# details about this)
|
||||||
|
|
||||||
|
iface_defaults = {
|
||||||
|
- 'rhel': {'ONBOOT': True, 'USERCTL': False, 'NM_CONTROLLED': False,
|
||||||
|
+ 'rhel': {'ONBOOT': True, 'USERCTL': False,
|
||||||
|
'BOOTPROTO': 'none'},
|
||||||
|
'suse': {'BOOTPROTO': 'static', 'STARTMODE': 'auto'},
|
||||||
|
}
|
||||||
|
@@ -925,7 +925,16 @@ class Renderer(renderer.Renderer):
|
||||||
|
# Distros configuring /etc/sysconfig/network as a file e.g. Centos
|
||||||
|
if sysconfig_path.endswith('network'):
|
||||||
|
util.ensure_dir(os.path.dirname(sysconfig_path))
|
||||||
|
- netcfg = [_make_header(), 'NETWORKING=yes']
|
||||||
|
+ netcfg = []
|
||||||
|
+ for line in util.load_file(sysconfig_path, quiet=True).split('\n'):
|
||||||
|
+ if 'cloud-init' in line:
|
||||||
|
+ break
|
||||||
|
+ if not line.startswith(('NETWORKING=',
|
||||||
|
+ 'IPV6_AUTOCONF=',
|
||||||
|
+ 'NETWORKING_IPV6=')):
|
||||||
|
+ netcfg.append(line)
|
||||||
|
+ # Now generate the cloud-init portion of sysconfig/network
|
||||||
|
+ netcfg.extend([_make_header(), 'NETWORKING=yes'])
|
||||||
|
if network_state.use_ipv6:
|
||||||
|
netcfg.append('NETWORKING_IPV6=yes')
|
||||||
|
netcfg.append('IPV6_AUTOCONF=no')
|
||||||
|
diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py
|
||||||
|
index 38d934d4..c67b5fcc 100644
|
||||||
|
--- a/tests/unittests/test_net.py
|
||||||
|
+++ b/tests/unittests/test_net.py
|
||||||
|
@@ -535,7 +535,6 @@ GATEWAY=172.19.3.254
|
||||||
|
HWADDR=fa:16:3e:ed:9a:59
|
||||||
|
IPADDR=172.19.1.34
|
||||||
|
NETMASK=255.255.252.0
|
||||||
|
-NM_CONTROLLED=no
|
||||||
|
ONBOOT=yes
|
||||||
|
TYPE=Ethernet
|
||||||
|
USERCTL=no
|
||||||
|
@@ -633,7 +632,6 @@ IPADDR=172.19.1.34
|
||||||
|
IPADDR1=10.0.0.10
|
||||||
|
NETMASK=255.255.252.0
|
||||||
|
NETMASK1=255.255.255.0
|
||||||
|
-NM_CONTROLLED=no
|
||||||
|
ONBOOT=yes
|
||||||
|
TYPE=Ethernet
|
||||||
|
USERCTL=no
|
||||||
|
@@ -756,7 +754,6 @@ IPV6_AUTOCONF=no
|
||||||
|
IPV6_DEFAULTGW=2001:DB8::1
|
||||||
|
IPV6_FORCE_ACCEPT_RA=no
|
||||||
|
NETMASK=255.255.252.0
|
||||||
|
-NM_CONTROLLED=no
|
||||||
|
ONBOOT=yes
|
||||||
|
TYPE=Ethernet
|
||||||
|
USERCTL=no
|
||||||
|
@@ -884,7 +881,6 @@ NETWORK_CONFIGS = {
|
||||||
|
BOOTPROTO=none
|
||||||
|
DEVICE=eth1
|
||||||
|
HWADDR=cf:d6:af:48:e8:80
|
||||||
|
- NM_CONTROLLED=no
|
||||||
|
ONBOOT=yes
|
||||||
|
TYPE=Ethernet
|
||||||
|
USERCTL=no"""),
|
||||||
|
@@ -901,7 +897,6 @@ NETWORK_CONFIGS = {
|
||||||
|
IPADDR=192.168.21.3
|
||||||
|
NETMASK=255.255.255.0
|
||||||
|
METRIC=10000
|
||||||
|
- NM_CONTROLLED=no
|
||||||
|
ONBOOT=yes
|
||||||
|
TYPE=Ethernet
|
||||||
|
USERCTL=no"""),
|
||||||
|
@@ -1032,7 +1027,6 @@ NETWORK_CONFIGS = {
|
||||||
|
IPV6_AUTOCONF=no
|
||||||
|
IPV6_FORCE_ACCEPT_RA=no
|
||||||
|
NETMASK=255.255.255.0
|
||||||
|
- NM_CONTROLLED=no
|
||||||
|
ONBOOT=yes
|
||||||
|
TYPE=Ethernet
|
||||||
|
USERCTL=no
|
||||||
|
@@ -1737,7 +1731,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true
|
||||||
|
DHCPV6C=yes
|
||||||
|
IPV6INIT=yes
|
||||||
|
MACADDR=aa:bb:cc:dd:ee:ff
|
||||||
|
- NM_CONTROLLED=no
|
||||||
|
ONBOOT=yes
|
||||||
|
TYPE=Bond
|
||||||
|
USERCTL=no"""),
|
||||||
|
@@ -1745,7 +1738,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true
|
||||||
|
BOOTPROTO=dhcp
|
||||||
|
DEVICE=bond0.200
|
||||||
|
DHCLIENT_SET_DEFAULT_ROUTE=no
|
||||||
|
- NM_CONTROLLED=no
|
||||||
|
ONBOOT=yes
|
||||||
|
PHYSDEV=bond0
|
||||||
|
USERCTL=no
|
||||||
|
@@ -1763,7 +1755,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true
|
||||||
|
IPV6_DEFAULTGW=2001:4800:78ff:1b::1
|
||||||
|
MACADDR=bb:bb:bb:bb:bb:aa
|
||||||
|
NETMASK=255.255.255.0
|
||||||
|
- NM_CONTROLLED=no
|
||||||
|
ONBOOT=yes
|
||||||
|
PRIO=22
|
||||||
|
STP=no
|
||||||
|
@@ -1773,7 +1764,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true
|
||||||
|
BOOTPROTO=none
|
||||||
|
DEVICE=eth0
|
||||||
|
HWADDR=c0:d6:9f:2c:e8:80
|
||||||
|
- NM_CONTROLLED=no
|
||||||
|
ONBOOT=yes
|
||||||
|
TYPE=Ethernet
|
||||||
|
USERCTL=no"""),
|
||||||
|
@@ -1790,7 +1780,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true
|
||||||
|
MTU=1500
|
||||||
|
NETMASK=255.255.255.0
|
||||||
|
NETMASK1=255.255.255.0
|
||||||
|
- NM_CONTROLLED=no
|
||||||
|
ONBOOT=yes
|
||||||
|
PHYSDEV=eth0
|
||||||
|
USERCTL=no
|
||||||
|
@@ -1800,7 +1789,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true
|
||||||
|
DEVICE=eth1
|
||||||
|
HWADDR=aa:d6:9f:2c:e8:80
|
||||||
|
MASTER=bond0
|
||||||
|
- NM_CONTROLLED=no
|
||||||
|
ONBOOT=yes
|
||||||
|
SLAVE=yes
|
||||||
|
TYPE=Ethernet
|
||||||
|
@@ -1810,7 +1798,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true
|
||||||
|
DEVICE=eth2
|
||||||
|
HWADDR=c0:bb:9f:2c:e8:80
|
||||||
|
MASTER=bond0
|
||||||
|
- NM_CONTROLLED=no
|
||||||
|
ONBOOT=yes
|
||||||
|
SLAVE=yes
|
||||||
|
TYPE=Ethernet
|
||||||
|
@@ -1820,7 +1807,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true
|
||||||
|
BRIDGE=br0
|
||||||
|
DEVICE=eth3
|
||||||
|
HWADDR=66:bb:9f:2c:e8:80
|
||||||
|
- NM_CONTROLLED=no
|
||||||
|
ONBOOT=yes
|
||||||
|
TYPE=Ethernet
|
||||||
|
USERCTL=no"""),
|
||||||
|
@@ -1829,7 +1815,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true
|
||||||
|
BRIDGE=br0
|
||||||
|
DEVICE=eth4
|
||||||
|
HWADDR=98:bb:9f:2c:e8:80
|
||||||
|
- NM_CONTROLLED=no
|
||||||
|
ONBOOT=yes
|
||||||
|
TYPE=Ethernet
|
||||||
|
USERCTL=no"""),
|
||||||
|
@@ -1838,7 +1823,6 @@ pre-down route del -net 10.0.0.0/8 gw 11.0.0.1 metric 3 || true
|
||||||
|
DEVICE=eth5
|
||||||
|
DHCLIENT_SET_DEFAULT_ROUTE=no
|
||||||
|
HWADDR=98:bb:9f:2c:e8:8a
|
||||||
|
- NM_CONTROLLED=no
|
||||||
|
ONBOOT=no
|
||||||
|
TYPE=Ethernet
|
||||||
|
USERCTL=no"""),
|
||||||
|
@@ -2294,7 +2278,6 @@ iface bond0 inet6 static
|
||||||
|
MTU=9000
|
||||||
|
NETMASK=255.255.255.0
|
||||||
|
NETMASK1=255.255.255.0
|
||||||
|
- NM_CONTROLLED=no
|
||||||
|
ONBOOT=yes
|
||||||
|
TYPE=Bond
|
||||||
|
USERCTL=no
|
||||||
|
@@ -2304,7 +2287,6 @@ iface bond0 inet6 static
|
||||||
|
DEVICE=bond0s0
|
||||||
|
HWADDR=aa:bb:cc:dd:e8:00
|
||||||
|
MASTER=bond0
|
||||||
|
- NM_CONTROLLED=no
|
||||||
|
ONBOOT=yes
|
||||||
|
SLAVE=yes
|
||||||
|
TYPE=Ethernet
|
||||||
|
@@ -2326,7 +2308,6 @@ iface bond0 inet6 static
|
||||||
|
DEVICE=bond0s1
|
||||||
|
HWADDR=aa:bb:cc:dd:e8:01
|
||||||
|
MASTER=bond0
|
||||||
|
- NM_CONTROLLED=no
|
||||||
|
ONBOOT=yes
|
||||||
|
SLAVE=yes
|
||||||
|
TYPE=Ethernet
|
||||||
|
@@ -2383,7 +2364,6 @@ iface bond0 inet6 static
|
||||||
|
BOOTPROTO=none
|
||||||
|
DEVICE=en0
|
||||||
|
HWADDR=aa:bb:cc:dd:e8:00
|
||||||
|
- NM_CONTROLLED=no
|
||||||
|
ONBOOT=yes
|
||||||
|
TYPE=Ethernet
|
||||||
|
USERCTL=no"""),
|
||||||
|
@@ -2402,7 +2382,6 @@ iface bond0 inet6 static
|
||||||
|
MTU=2222
|
||||||
|
NETMASK=255.255.255.0
|
||||||
|
NETMASK1=255.255.255.0
|
||||||
|
- NM_CONTROLLED=no
|
||||||
|
ONBOOT=yes
|
||||||
|
PHYSDEV=en0
|
||||||
|
USERCTL=no
|
||||||
|
@@ -2467,7 +2446,6 @@ iface bond0 inet6 static
|
||||||
|
DEVICE=br0
|
||||||
|
IPADDR=192.168.2.2
|
||||||
|
NETMASK=255.255.255.0
|
||||||
|
- NM_CONTROLLED=no
|
||||||
|
ONBOOT=yes
|
||||||
|
PRIO=22
|
||||||
|
STP=no
|
||||||
|
@@ -2591,7 +2569,6 @@ iface bond0 inet6 static
|
||||||
|
HWADDR=52:54:00:12:34:00
|
||||||
|
IPADDR=192.168.1.2
|
||||||
|
NETMASK=255.255.255.0
|
||||||
|
- NM_CONTROLLED=no
|
||||||
|
ONBOOT=no
|
||||||
|
TYPE=Ethernet
|
||||||
|
USERCTL=no
|
||||||
|
@@ -2601,7 +2578,6 @@ iface bond0 inet6 static
|
||||||
|
DEVICE=eth1
|
||||||
|
HWADDR=52:54:00:12:34:aa
|
||||||
|
MTU=1480
|
||||||
|
- NM_CONTROLLED=no
|
||||||
|
ONBOOT=yes
|
||||||
|
TYPE=Ethernet
|
||||||
|
USERCTL=no
|
||||||
|
@@ -2610,7 +2586,6 @@ iface bond0 inet6 static
|
||||||
|
BOOTPROTO=none
|
||||||
|
DEVICE=eth2
|
||||||
|
HWADDR=52:54:00:12:34:ff
|
||||||
|
- NM_CONTROLLED=no
|
||||||
|
ONBOOT=no
|
||||||
|
TYPE=Ethernet
|
||||||
|
USERCTL=no
|
||||||
|
@@ -3027,7 +3002,6 @@ class TestRhelSysConfigRendering(CiTestCase):
|
||||||
|
BOOTPROTO=dhcp
|
||||||
|
DEVICE=eth1000
|
||||||
|
HWADDR=07-1c-c6-75-a4-be
|
||||||
|
-NM_CONTROLLED=no
|
||||||
|
ONBOOT=yes
|
||||||
|
TYPE=Ethernet
|
||||||
|
USERCTL=no
|
||||||
|
@@ -3148,7 +3122,6 @@ GATEWAY=10.0.2.2
|
||||||
|
HWADDR=52:54:00:12:34:00
|
||||||
|
IPADDR=10.0.2.15
|
||||||
|
NETMASK=255.255.255.0
|
||||||
|
-NM_CONTROLLED=no
|
||||||
|
ONBOOT=yes
|
||||||
|
TYPE=Ethernet
|
||||||
|
USERCTL=no
|
||||||
|
@@ -3218,7 +3191,6 @@ USERCTL=no
|
||||||
|
#
|
||||||
|
BOOTPROTO=dhcp
|
||||||
|
DEVICE=eth0
|
||||||
|
-NM_CONTROLLED=no
|
||||||
|
ONBOOT=yes
|
||||||
|
TYPE=Ethernet
|
||||||
|
USERCTL=no
|
||||||
|
--
|
||||||
|
2.27.0
|
||||||
|
|
69
SOURCES/0003-limit-permissions-on-def_log_file.patch
Normal file
69
SOURCES/0003-limit-permissions-on-def_log_file.patch
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
From 680ebcb46d1db6f02f2b21c158b4a9af2d789ba3 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Eduardo Otubo <otubo@redhat.com>
|
||||||
|
Date: Fri, 7 May 2021 13:36:08 +0200
|
||||||
|
Subject: limit permissions on def_log_file
|
||||||
|
|
||||||
|
This sets a default mode of 0600 on def_log_file, and makes this
|
||||||
|
configurable via the def_log_file_mode option in cloud.cfg.
|
||||||
|
|
||||||
|
LP: #1541196
|
||||||
|
Resolves: rhbz#1424612
|
||||||
|
X-approved-upstream: true
|
||||||
|
|
||||||
|
Conflicts 21.1:
|
||||||
|
cloudinit/stages.py: adjusting call of ensure_file() to use more
|
||||||
|
recent version
|
||||||
|
|
||||||
|
Signed-off-by: Eduardo Otubo <otubo@redhat.com>
|
||||||
|
---
|
||||||
|
cloudinit/settings.py | 1 +
|
||||||
|
cloudinit/stages.py | 1 +
|
||||||
|
doc/examples/cloud-config.txt | 4 ++++
|
||||||
|
3 files changed, 6 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/cloudinit/settings.py b/cloudinit/settings.py
|
||||||
|
index e690c0fd..43a1490c 100644
|
||||||
|
--- a/cloudinit/settings.py
|
||||||
|
+++ b/cloudinit/settings.py
|
||||||
|
@@ -46,6 +46,7 @@ CFG_BUILTIN = {
|
||||||
|
'None',
|
||||||
|
],
|
||||||
|
'def_log_file': '/var/log/cloud-init.log',
|
||||||
|
+ 'def_log_file_mode': 0o600,
|
||||||
|
'log_cfgs': [],
|
||||||
|
'mount_default_fields': [None, None, 'auto', 'defaults,nofail', '0', '2'],
|
||||||
|
'ssh_deletekeys': False,
|
||||||
|
diff --git a/cloudinit/stages.py b/cloudinit/stages.py
|
||||||
|
index 3ef4491c..83e25dd1 100644
|
||||||
|
--- a/cloudinit/stages.py
|
||||||
|
+++ b/cloudinit/stages.py
|
||||||
|
@@ -147,6 +147,7 @@ class Init(object):
|
||||||
|
def _initialize_filesystem(self):
|
||||||
|
util.ensure_dirs(self._initial_subdirs())
|
||||||
|
log_file = util.get_cfg_option_str(self.cfg, 'def_log_file')
|
||||||
|
+ log_file_mode = util.get_cfg_option_int(self.cfg, 'def_log_file_mode')
|
||||||
|
if log_file:
|
||||||
|
util.ensure_file(log_file, preserve_mode=True)
|
||||||
|
perms = self.cfg.get('syslog_fix_perms')
|
||||||
|
diff --git a/doc/examples/cloud-config.txt b/doc/examples/cloud-config.txt
|
||||||
|
index de9a0f87..bb33ad45 100644
|
||||||
|
--- a/doc/examples/cloud-config.txt
|
||||||
|
+++ b/doc/examples/cloud-config.txt
|
||||||
|
@@ -414,10 +414,14 @@ timezone: US/Eastern
|
||||||
|
# if syslog_fix_perms is a list, it will iterate through and use the
|
||||||
|
# first pair that does not raise error.
|
||||||
|
#
|
||||||
|
+# 'def_log_file' will be created with mode 'def_log_file_mode', which
|
||||||
|
+# is specified as a numeric value and defaults to 0600.
|
||||||
|
+#
|
||||||
|
# the default values are '/var/log/cloud-init.log' and 'syslog:adm'
|
||||||
|
# the value of 'def_log_file' should match what is configured in logging
|
||||||
|
# if either is empty, then no change of ownership will be done
|
||||||
|
def_log_file: /var/log/my-logging-file.log
|
||||||
|
+def_log_file_mode: 0600
|
||||||
|
syslog_fix_perms: syslog:root
|
||||||
|
|
||||||
|
# you can set passwords for a user or multiple users
|
||||||
|
--
|
||||||
|
2.27.0
|
||||||
|
|
@ -0,0 +1,103 @@
|
|||||||
|
From 83394f05a01b5e1f8e520213537558c1cb5d9051 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Eduardo Otubo <otubo@redhat.com>
|
||||||
|
Date: Thu, 1 Jul 2021 12:01:34 +0200
|
||||||
|
Subject: [PATCH] Fix requiring device-number on EC2 derivatives (#836)
|
||||||
|
|
||||||
|
RH-Author: Eduardo Otubo <otubo@redhat.com>
|
||||||
|
RH-MergeRequest: 3: Fix requiring device-number on EC2 derivatives (#836)
|
||||||
|
RH-Commit: [1/1] a0b7af14a2bc6480bb844a496007737b8807f666 (otubo/cloud-init-src)
|
||||||
|
RH-Bugzilla: 1943511
|
||||||
|
RH-Acked-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
|
||||||
|
RH-Acked-by: Mohamed Gamal Morsy <mmorsy@redhat.com>
|
||||||
|
|
||||||
|
commit 9bd19645a61586b82e86db6f518dd05c3363b17f
|
||||||
|
Author: James Falcon <TheRealFalcon@users.noreply.github.com>
|
||||||
|
Date: Mon Mar 8 14:09:47 2021 -0600
|
||||||
|
|
||||||
|
Fix requiring device-number on EC2 derivatives (#836)
|
||||||
|
|
||||||
|
#342 (70dbccbb) introduced the ability to determine route-metrics based on
|
||||||
|
the `device-number` provided by the EC2 IMDS. Not all datasources that
|
||||||
|
subclass EC2 will have this attribute, so allow the old behavior if
|
||||||
|
`device-number` is not present.
|
||||||
|
|
||||||
|
LP: #1917875
|
||||||
|
|
||||||
|
Signed-off-by: Eduardo Otubo <otubo@redhat.com>
|
||||||
|
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||||
|
---
|
||||||
|
cloudinit/sources/DataSourceEc2.py | 3 +-
|
||||||
|
.../unittests/test_datasource/test_aliyun.py | 30 +++++++++++++++++++
|
||||||
|
2 files changed, 32 insertions(+), 1 deletion(-)
|
||||||
|
|
||||||
|
diff --git a/cloudinit/sources/DataSourceEc2.py b/cloudinit/sources/DataSourceEc2.py
|
||||||
|
index 1930a509..a2105dc7 100644
|
||||||
|
--- a/cloudinit/sources/DataSourceEc2.py
|
||||||
|
+++ b/cloudinit/sources/DataSourceEc2.py
|
||||||
|
@@ -765,13 +765,14 @@ def convert_ec2_metadata_network_config(
|
||||||
|
netcfg['ethernets'][nic_name] = dev_config
|
||||||
|
return netcfg
|
||||||
|
# Apply network config for all nics and any secondary IPv4/v6 addresses
|
||||||
|
+ nic_idx = 0
|
||||||
|
for mac, nic_name in sorted(macs_to_nics.items()):
|
||||||
|
nic_metadata = macs_metadata.get(mac)
|
||||||
|
if not nic_metadata:
|
||||||
|
continue # Not a physical nic represented in metadata
|
||||||
|
# device-number is zero-indexed, we want it 1-indexed for the
|
||||||
|
# multiplication on the following line
|
||||||
|
- nic_idx = int(nic_metadata['device-number']) + 1
|
||||||
|
+ nic_idx = int(nic_metadata.get('device-number', nic_idx)) + 1
|
||||||
|
dhcp_override = {'route-metric': nic_idx * 100}
|
||||||
|
dev_config = {'dhcp4': True, 'dhcp4-overrides': dhcp_override,
|
||||||
|
'dhcp6': False,
|
||||||
|
diff --git a/tests/unittests/test_datasource/test_aliyun.py b/tests/unittests/test_datasource/test_aliyun.py
|
||||||
|
index eb2828d5..cab1ac2b 100644
|
||||||
|
--- a/tests/unittests/test_datasource/test_aliyun.py
|
||||||
|
+++ b/tests/unittests/test_datasource/test_aliyun.py
|
||||||
|
@@ -7,6 +7,7 @@ from unittest import mock
|
||||||
|
|
||||||
|
from cloudinit import helpers
|
||||||
|
from cloudinit.sources import DataSourceAliYun as ay
|
||||||
|
+from cloudinit.sources.DataSourceEc2 import convert_ec2_metadata_network_config
|
||||||
|
from cloudinit.tests import helpers as test_helpers
|
||||||
|
|
||||||
|
DEFAULT_METADATA = {
|
||||||
|
@@ -183,6 +184,35 @@ class TestAliYunDatasource(test_helpers.HttprettyTestCase):
|
||||||
|
self.assertEqual(ay.parse_public_keys(public_keys),
|
||||||
|
public_keys['key-pair-0']['openssh-key'])
|
||||||
|
|
||||||
|
+ def test_route_metric_calculated_without_device_number(self):
|
||||||
|
+ """Test that route-metric code works without `device-number`
|
||||||
|
+
|
||||||
|
+ `device-number` is part of EC2 metadata, but not supported on aliyun.
|
||||||
|
+ Attempting to access it will raise a KeyError.
|
||||||
|
+
|
||||||
|
+ LP: #1917875
|
||||||
|
+ """
|
||||||
|
+ netcfg = convert_ec2_metadata_network_config(
|
||||||
|
+ {"interfaces": {"macs": {
|
||||||
|
+ "06:17:04:d7:26:09": {
|
||||||
|
+ "interface-id": "eni-e44ef49e",
|
||||||
|
+ },
|
||||||
|
+ "06:17:04:d7:26:08": {
|
||||||
|
+ "interface-id": "eni-e44ef49f",
|
||||||
|
+ }
|
||||||
|
+ }}},
|
||||||
|
+ macs_to_nics={
|
||||||
|
+ '06:17:04:d7:26:09': 'eth0',
|
||||||
|
+ '06:17:04:d7:26:08': 'eth1',
|
||||||
|
+ }
|
||||||
|
+ )
|
||||||
|
+
|
||||||
|
+ met0 = netcfg['ethernets']['eth0']['dhcp4-overrides']['route-metric']
|
||||||
|
+ met1 = netcfg['ethernets']['eth1']['dhcp4-overrides']['route-metric']
|
||||||
|
+
|
||||||
|
+ # route-metric numbers should be 100 apart
|
||||||
|
+ assert 100 == abs(met0 - met1)
|
||||||
|
+
|
||||||
|
|
||||||
|
class TestIsAliYun(test_helpers.CiTestCase):
|
||||||
|
ALIYUN_PRODUCT = 'Alibaba Cloud ECS'
|
||||||
|
--
|
||||||
|
2.27.0
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,65 @@
|
|||||||
|
From 5069e58c009bc8c689f00de35391ae6d860197a4 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Emanuele Giuseppe Esposito <eesposit@redhat.com>
|
||||||
|
Date: Thu, 20 May 2021 08:53:55 +0200
|
||||||
|
Subject: [PATCH 1/2] rhel/cloud.cfg: remove ssh_genkeytypes in settings.py and
|
||||||
|
set in cloud.cfg
|
||||||
|
|
||||||
|
RH-Author: Emanuele Giuseppe Esposito <eesposit@redhat.com>
|
||||||
|
RH-MergeRequest: 16: rhel/cloud.cfg: remove ssh_genkeytypes in settings.py and set in cloud.cfg
|
||||||
|
RH-Commit: [1/1] 67a4904f4d7918be4c9b3c3dbf340b3ecb9e8786
|
||||||
|
RH-Bugzilla: 1970909
|
||||||
|
RH-Acked-by: Mohamed Gamal Morsy <mmorsy@redhat.com>
|
||||||
|
RH-Acked-by: Eduardo Otubo <otubo@redhat.com>
|
||||||
|
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
|
||||||
|
|
||||||
|
Currently genkeytypes in cloud.cfg is set to None, so together with
|
||||||
|
ssh_deletekeys=1 cloudinit on first boot it will just delete the existing
|
||||||
|
keys and not generate new ones.
|
||||||
|
|
||||||
|
Just removing that property in cloud.cfg is not enough, because
|
||||||
|
settings.py provides another empty default value that will be used
|
||||||
|
instead, resulting to no key generated even when the property is not defined.
|
||||||
|
|
||||||
|
Removing genkeytypes also in settings.py will default to GENERATE_KEY_NAMES,
|
||||||
|
but since we want only 'rsa', 'ecdsa' and 'ed25519', add back genkeytypes in
|
||||||
|
cloud.cfg with the above defaults.
|
||||||
|
|
||||||
|
Also remove ssh_deletekeys in settings.py as we always need
|
||||||
|
to 1 (and it also defaults to 1).
|
||||||
|
|
||||||
|
Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
|
||||||
|
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||||
|
---
|
||||||
|
cloudinit/settings.py | 2 --
|
||||||
|
rhel/cloud.cfg | 2 +-
|
||||||
|
2 files changed, 1 insertion(+), 3 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/cloudinit/settings.py b/cloudinit/settings.py
|
||||||
|
index 43a1490c..2acf2615 100644
|
||||||
|
--- a/cloudinit/settings.py
|
||||||
|
+++ b/cloudinit/settings.py
|
||||||
|
@@ -49,8 +49,6 @@ CFG_BUILTIN = {
|
||||||
|
'def_log_file_mode': 0o600,
|
||||||
|
'log_cfgs': [],
|
||||||
|
'mount_default_fields': [None, None, 'auto', 'defaults,nofail', '0', '2'],
|
||||||
|
- 'ssh_deletekeys': False,
|
||||||
|
- 'ssh_genkeytypes': [],
|
||||||
|
'syslog_fix_perms': [],
|
||||||
|
'system_info': {
|
||||||
|
'paths': {
|
||||||
|
diff --git a/rhel/cloud.cfg b/rhel/cloud.cfg
|
||||||
|
index 9ecba215..cbee197a 100644
|
||||||
|
--- a/rhel/cloud.cfg
|
||||||
|
+++ b/rhel/cloud.cfg
|
||||||
|
@@ -7,7 +7,7 @@ ssh_pwauth: 0
|
||||||
|
mount_default_fields: [~, ~, 'auto', 'defaults,nofail,x-systemd.requires=cloud-init.service', '0', '2']
|
||||||
|
resize_rootfs_tmp: /dev
|
||||||
|
ssh_deletekeys: 1
|
||||||
|
-ssh_genkeytypes: ~
|
||||||
|
+ssh_genkeytypes: ['rsa', 'ecdsa', 'ed25519']
|
||||||
|
syslog_fix_perms: ~
|
||||||
|
disable_vmware_customization: false
|
||||||
|
|
||||||
|
--
|
||||||
|
2.27.0
|
||||||
|
|
@ -0,0 +1,651 @@
|
|||||||
|
From 857009723f14e9ad2f5f4c8614d72982b00ec27d Mon Sep 17 00:00:00 2001
|
||||||
|
From: Emanuele Giuseppe Esposito <eesposit@redhat.com>
|
||||||
|
Date: Mon, 12 Jul 2021 21:47:37 +0200
|
||||||
|
Subject: [PATCH 2/2] ssh-util: allow cloudinit to merge all ssh keys into a
|
||||||
|
custom user file, defined in AuthorizedKeysFile (#937)
|
||||||
|
|
||||||
|
RH-Author: Emanuele Giuseppe Esposito <eesposit@redhat.com>
|
||||||
|
RH-MergeRequest: 5: ssh-util: allow cloudinit to merge all ssh keys into a custom user file, defined in AuthorizedKeysFile (#937)
|
||||||
|
RH-Commit: [1/1] 3ed352e47c34e2ed2a1f9f5d68bc8b8f9a1365a6 (eesposit/cloud-init-centos-)
|
||||||
|
RH-Bugzilla: 1979099
|
||||||
|
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||||
|
RH-Acked-by: Mohamed Gamal Morsy <mmorsy@redhat.com>
|
||||||
|
|
||||||
|
Conflicts: upstream patch modifies tests/integration_tests/util.py, that is
|
||||||
|
not present in RHEL.
|
||||||
|
|
||||||
|
commit 9b52405c6f0de5e00d5ee9c1d13540425d8f6bf5
|
||||||
|
Author: Emanuele Giuseppe Esposito <eesposit@redhat.com>
|
||||||
|
Date: Mon Jul 12 20:21:02 2021 +0200
|
||||||
|
|
||||||
|
ssh-util: allow cloudinit to merge all ssh keys into a custom user file, defined in AuthorizedKeysFile (#937)
|
||||||
|
|
||||||
|
This patch aims to fix LP1911680, by analyzing the files provided
|
||||||
|
in sshd_config and merge all keys into an user-specific file. Also
|
||||||
|
introduces additional tests to cover this specific case.
|
||||||
|
|
||||||
|
The file is picked by analyzing the path given in AuthorizedKeysFile.
|
||||||
|
|
||||||
|
If it points inside the current user folder (path is /home/user/*), it
|
||||||
|
means it is an user-specific file, so we can copy all user-keys there.
|
||||||
|
If it contains a %u or %h, it means that there will be a specific
|
||||||
|
authorized_keys file for each user, so we can copy all user-keys there.
|
||||||
|
If no path points to an user-specific file, for example when only
|
||||||
|
/etc/ssh/authorized_keys is given, default to ~/.ssh/authorized_keys.
|
||||||
|
Note that if there are more than a single user-specific file, the last
|
||||||
|
one will be picked.
|
||||||
|
|
||||||
|
Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
|
||||||
|
Co-authored-by: James Falcon <therealfalcon@gmail.com>
|
||||||
|
|
||||||
|
LP: #1911680
|
||||||
|
RHBZ:1862967
|
||||||
|
|
||||||
|
Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
|
||||||
|
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||||
|
---
|
||||||
|
cloudinit/ssh_util.py | 22 +-
|
||||||
|
.../assets/keys/id_rsa.test1 | 38 +++
|
||||||
|
.../assets/keys/id_rsa.test1.pub | 1 +
|
||||||
|
.../assets/keys/id_rsa.test2 | 38 +++
|
||||||
|
.../assets/keys/id_rsa.test2.pub | 1 +
|
||||||
|
.../assets/keys/id_rsa.test3 | 38 +++
|
||||||
|
.../assets/keys/id_rsa.test3.pub | 1 +
|
||||||
|
.../modules/test_ssh_keysfile.py | 85 ++++++
|
||||||
|
tests/unittests/test_sshutil.py | 246 +++++++++++++++++-
|
||||||
|
9 files changed, 456 insertions(+), 14 deletions(-)
|
||||||
|
create mode 100644 tests/integration_tests/assets/keys/id_rsa.test1
|
||||||
|
create mode 100644 tests/integration_tests/assets/keys/id_rsa.test1.pub
|
||||||
|
create mode 100644 tests/integration_tests/assets/keys/id_rsa.test2
|
||||||
|
create mode 100644 tests/integration_tests/assets/keys/id_rsa.test2.pub
|
||||||
|
create mode 100644 tests/integration_tests/assets/keys/id_rsa.test3
|
||||||
|
create mode 100644 tests/integration_tests/assets/keys/id_rsa.test3.pub
|
||||||
|
create mode 100644 tests/integration_tests/modules/test_ssh_keysfile.py
|
||||||
|
|
||||||
|
diff --git a/cloudinit/ssh_util.py b/cloudinit/ssh_util.py
|
||||||
|
index c08042d6..89057262 100644
|
||||||
|
--- a/cloudinit/ssh_util.py
|
||||||
|
+++ b/cloudinit/ssh_util.py
|
||||||
|
@@ -252,13 +252,15 @@ def render_authorizedkeysfile_paths(value, homedir, username):
|
||||||
|
def extract_authorized_keys(username, sshd_cfg_file=DEF_SSHD_CFG):
|
||||||
|
(ssh_dir, pw_ent) = users_ssh_info(username)
|
||||||
|
default_authorizedkeys_file = os.path.join(ssh_dir, 'authorized_keys')
|
||||||
|
+ user_authorizedkeys_file = default_authorizedkeys_file
|
||||||
|
auth_key_fns = []
|
||||||
|
with util.SeLinuxGuard(ssh_dir, recursive=True):
|
||||||
|
try:
|
||||||
|
ssh_cfg = parse_ssh_config_map(sshd_cfg_file)
|
||||||
|
+ key_paths = ssh_cfg.get("authorizedkeysfile",
|
||||||
|
+ "%h/.ssh/authorized_keys")
|
||||||
|
auth_key_fns = render_authorizedkeysfile_paths(
|
||||||
|
- ssh_cfg.get("authorizedkeysfile", "%h/.ssh/authorized_keys"),
|
||||||
|
- pw_ent.pw_dir, username)
|
||||||
|
+ key_paths, pw_ent.pw_dir, username)
|
||||||
|
|
||||||
|
except (IOError, OSError):
|
||||||
|
# Give up and use a default key filename
|
||||||
|
@@ -267,8 +269,22 @@ def extract_authorized_keys(username, sshd_cfg_file=DEF_SSHD_CFG):
|
||||||
|
"config from %r, using 'AuthorizedKeysFile' file "
|
||||||
|
"%r instead", DEF_SSHD_CFG, auth_key_fns[0])
|
||||||
|
|
||||||
|
+ # check if one of the keys is the user's one
|
||||||
|
+ for key_path, auth_key_fn in zip(key_paths.split(), auth_key_fns):
|
||||||
|
+ if any([
|
||||||
|
+ '%u' in key_path,
|
||||||
|
+ '%h' in key_path,
|
||||||
|
+ auth_key_fn.startswith('{}/'.format(pw_ent.pw_dir))
|
||||||
|
+ ]):
|
||||||
|
+ user_authorizedkeys_file = auth_key_fn
|
||||||
|
+
|
||||||
|
+ if user_authorizedkeys_file != default_authorizedkeys_file:
|
||||||
|
+ LOG.debug(
|
||||||
|
+ "AuthorizedKeysFile has an user-specific authorized_keys, "
|
||||||
|
+ "using %s", user_authorizedkeys_file)
|
||||||
|
+
|
||||||
|
# always store all the keys in the user's private file
|
||||||
|
- return (default_authorizedkeys_file, parse_authorized_keys(auth_key_fns))
|
||||||
|
+ return (user_authorizedkeys_file, parse_authorized_keys(auth_key_fns))
|
||||||
|
|
||||||
|
|
||||||
|
def setup_user_keys(keys, username, options=None):
|
||||||
|
diff --git a/tests/integration_tests/assets/keys/id_rsa.test1 b/tests/integration_tests/assets/keys/id_rsa.test1
|
||||||
|
new file mode 100644
|
||||||
|
index 00000000..bd4c822e
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/tests/integration_tests/assets/keys/id_rsa.test1
|
||||||
|
@@ -0,0 +1,38 @@
|
||||||
|
+-----BEGIN OPENSSH PRIVATE KEY-----
|
||||||
|
+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
|
||||||
|
+CHbTWbsFrHR1qFAAAACmphbWVzQG5ld3Q=
|
||||||
|
+-----END OPENSSH PRIVATE KEY-----
|
||||||
|
diff --git a/tests/integration_tests/assets/keys/id_rsa.test1.pub b/tests/integration_tests/assets/keys/id_rsa.test1.pub
|
||||||
|
new file mode 100644
|
||||||
|
index 00000000..3d2e26e1
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/tests/integration_tests/assets/keys/id_rsa.test1.pub
|
||||||
|
@@ -0,0 +1 @@
|
||||||
|
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC1GUb3ponbdRG8CA79sGy4uX6Wq5zfnRpLBX3z+Ly+W86fkZVwfJ63+tdCDiVnizSjAbeRbJAVjye9OT4b5Q1Tx83RqcDMEOL7gzOx6OQX2xyNMwWZdWsikgKpXdthA2M+/qv65tB2QPTV27d4H23n/OXziC2yGnSEF2h/LPy7X8Dbmzt9VTrsbIjs90q9pL7K8lIidmdvZ71VDN8kL6oCc3uBRlq0EqN2BS0l6JRR4NpWdpLXtvRqhP2IE7SwhxC05MGViUKMW3VMAwtnrgePdJ8ZkHtiPRn4vMUHYhZfXPOyMjrxiRg8o5Iv81iFBT17nmQlDtaeeA0dj/af8Dt00pIUOaAzlz0haB5nt+Omx8hgCgn8IDEUg0P48Qd3WAJLrGgSFpRXKHlYf9eTAq/WfHgCJnYEUIT7vmTJJEtlQn7nLSvcNTmS0xd5RHNUg/um7RHwMK6X4ZT4z/5MfJa0AQ6B5o0np9imjaKkOFuZNi3eSTaUwhqlHEYEWz7fux0= test1@host
|
||||||
|
diff --git a/tests/integration_tests/assets/keys/id_rsa.test2 b/tests/integration_tests/assets/keys/id_rsa.test2
|
||||||
|
new file mode 100644
|
||||||
|
index 00000000..5854d901
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/tests/integration_tests/assets/keys/id_rsa.test2
|
||||||
|
@@ -0,0 +1,38 @@
|
||||||
|
+-----BEGIN OPENSSH PRIVATE KEY-----
|
||||||
|
+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
|
||||||
|
+tZRSm2GEgnDGAvAAAACmphbWVzQG5ld3Q=
|
||||||
|
+-----END OPENSSH PRIVATE KEY-----
|
||||||
|
diff --git a/tests/integration_tests/assets/keys/id_rsa.test2.pub b/tests/integration_tests/assets/keys/id_rsa.test2.pub
|
||||||
|
new file mode 100644
|
||||||
|
index 00000000..f3831a57
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/tests/integration_tests/assets/keys/id_rsa.test2.pub
|
||||||
|
@@ -0,0 +1 @@
|
||||||
|
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC8rnQPY9Y5ziKTIdVElLq0OGrOMvlwqKK8gPinVfwFgJXDzdcAQY4uci1TJVcc0AOWHp+lWrU1joDYlW3KCg8XpkXHymHshYyaeEN2fEsvIaxuF3UzW2JckP9H7dacYdEng8qtBq8wuCodGuJ5XdBVV+MVJ6jqNf/hOu4/pma8hMxlYmtdoamHEn+k/KQR2Q6LwCYpT0U2+KiPI9Lac22P0H/rfkh2Ba+t3tV/lhyzD0xHnktZKJ3BrznpEfrZiXoukQZMebWUmIyTW7zwk9Kq+iGFpSQsqQWlxDBwHSbvpbUo7KWUmyZfxs1euVmwj5aKJgjteXm9CbbXsMS415q+08C0MzG7weZODZQnnk1rF6Ft97aXHaTmRgYbDeLU7U5U3alnb84HvUu5xh3/mrE9rPTfCzBwY4lgY+Q1zjS90RL9Jxzti3weydm7OqTI6DOfQeJQLOhhRgthOkt/7IabDFLIARjTnpo5+QKxugoc4qI6aUnE1plkVCRfV696ngM= test2@host
|
||||||
|
diff --git a/tests/integration_tests/assets/keys/id_rsa.test3 b/tests/integration_tests/assets/keys/id_rsa.test3
|
||||||
|
new file mode 100644
|
||||||
|
index 00000000..2596c762
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/tests/integration_tests/assets/keys/id_rsa.test3
|
||||||
|
@@ -0,0 +1,38 @@
|
||||||
|
+-----BEGIN OPENSSH PRIVATE KEY-----
|
||||||
|
+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
|
||||||
|
+eauhOY52PS/BcAAAAKamFtZXNAbmV3dAE=
|
||||||
|
+-----END OPENSSH PRIVATE KEY-----
|
||||||
|
diff --git a/tests/integration_tests/assets/keys/id_rsa.test3.pub b/tests/integration_tests/assets/keys/id_rsa.test3.pub
|
||||||
|
new file mode 100644
|
||||||
|
index 00000000..057db632
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/tests/integration_tests/assets/keys/id_rsa.test3.pub
|
||||||
|
@@ -0,0 +1 @@
|
||||||
|
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCk8bgx2RhAoPnv+qt4WuH0ZELbbLrqpk5ZlZGMLzzuutu8HM7r2FXImlMheV4kS+laIdhyMxHkbo00Wyc21nh/EOqZJzi9wWPncmwT9c2osqrqmxdp0Jvm+Q2kZvED5nlsmXMn3r0+AkggRuBzzqx6LiSBHYy49aq1ltjkaSk0JOpa4th4Ur7XigWu4DafJYf0w4hEMcr93n3umwfL4tMy3KY7tk+E7nvVpsrDqO+/CJJ4PFUT2RXsoBAi4z39LeB+2+BBCuifcYvfimCYhpt1IZ1t8eoYOiivImGVuq4lkQsE3bfoqBE1MICNW9TOONCvV5E/fGywbBU7oQIEYJAuX9piiACC3CfCP2Jeq1+IsrcTCWCOq5Tj4lDQJW0uEbeAhkH6qgxOFyjSmYdOuO19ALCvO2wEEW6dJrb8Ky25XWZDk7lmtnoAKj3I9EE2Sezr4KIp20y0K3OLeTZEPP2OliY9xqTTcuvsiR0LVOnr6MD7//I8dI7WjgKpbz0hDM0= test3@host
|
||||||
|
diff --git a/tests/integration_tests/modules/test_ssh_keysfile.py b/tests/integration_tests/modules/test_ssh_keysfile.py
|
||||||
|
new file mode 100644
|
||||||
|
index 00000000..f82d7649
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/tests/integration_tests/modules/test_ssh_keysfile.py
|
||||||
|
@@ -0,0 +1,85 @@
|
||||||
|
+import paramiko
|
||||||
|
+import pytest
|
||||||
|
+from io import StringIO
|
||||||
|
+from paramiko.ssh_exception import SSHException
|
||||||
|
+
|
||||||
|
+from tests.integration_tests.instances import IntegrationInstance
|
||||||
|
+from tests.integration_tests.util import get_test_rsa_keypair
|
||||||
|
+
|
||||||
|
+TEST_USER1_KEYS = get_test_rsa_keypair('test1')
|
||||||
|
+TEST_USER2_KEYS = get_test_rsa_keypair('test2')
|
||||||
|
+TEST_DEFAULT_KEYS = get_test_rsa_keypair('test3')
|
||||||
|
+
|
||||||
|
+USERDATA = """\
|
||||||
|
+#cloud-config
|
||||||
|
+bootcmd:
|
||||||
|
+ - sed -i 's;#AuthorizedKeysFile.*;AuthorizedKeysFile /etc/ssh/authorized_keys %h/.ssh/authorized_keys2;' /etc/ssh/sshd_config
|
||||||
|
+ssh_authorized_keys:
|
||||||
|
+ - {default}
|
||||||
|
+users:
|
||||||
|
+- default
|
||||||
|
+- name: test_user1
|
||||||
|
+ ssh_authorized_keys:
|
||||||
|
+ - {user1}
|
||||||
|
+- name: test_user2
|
||||||
|
+ ssh_authorized_keys:
|
||||||
|
+ - {user2}
|
||||||
|
+""".format( # noqa: E501
|
||||||
|
+ default=TEST_DEFAULT_KEYS.public_key,
|
||||||
|
+ user1=TEST_USER1_KEYS.public_key,
|
||||||
|
+ user2=TEST_USER2_KEYS.public_key,
|
||||||
|
+)
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+@pytest.mark.ubuntu
|
||||||
|
+@pytest.mark.user_data(USERDATA)
|
||||||
|
+def test_authorized_keys(client: IntegrationInstance):
|
||||||
|
+ expected_keys = [
|
||||||
|
+ ('test_user1', '/home/test_user1/.ssh/authorized_keys2',
|
||||||
|
+ TEST_USER1_KEYS),
|
||||||
|
+ ('test_user2', '/home/test_user2/.ssh/authorized_keys2',
|
||||||
|
+ TEST_USER2_KEYS),
|
||||||
|
+ ('ubuntu', '/home/ubuntu/.ssh/authorized_keys2',
|
||||||
|
+ TEST_DEFAULT_KEYS),
|
||||||
|
+ ('root', '/root/.ssh/authorized_keys2', TEST_DEFAULT_KEYS),
|
||||||
|
+ ]
|
||||||
|
+
|
||||||
|
+ for user, filename, keys in expected_keys:
|
||||||
|
+ contents = client.read_from_file(filename)
|
||||||
|
+ if user in ['ubuntu', 'root']:
|
||||||
|
+ # Our personal public key gets added by pycloudlib
|
||||||
|
+ lines = contents.split('\n')
|
||||||
|
+ assert len(lines) == 2
|
||||||
|
+ assert keys.public_key.strip() in contents
|
||||||
|
+ else:
|
||||||
|
+ assert contents.strip() == keys.public_key.strip()
|
||||||
|
+
|
||||||
|
+ # Ensure we can actually connect
|
||||||
|
+ ssh = paramiko.SSHClient()
|
||||||
|
+ ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||||
|
+ paramiko_key = paramiko.RSAKey.from_private_key(StringIO(
|
||||||
|
+ keys.private_key))
|
||||||
|
+
|
||||||
|
+ # Will fail with AuthenticationException if
|
||||||
|
+ # we cannot connect
|
||||||
|
+ ssh.connect(
|
||||||
|
+ client.instance.ip,
|
||||||
|
+ username=user,
|
||||||
|
+ pkey=paramiko_key,
|
||||||
|
+ look_for_keys=False,
|
||||||
|
+ allow_agent=False,
|
||||||
|
+ )
|
||||||
|
+
|
||||||
|
+ # Ensure other uses can't connect using our key
|
||||||
|
+ other_users = [u[0] for u in expected_keys if u[2] != keys]
|
||||||
|
+ for other_user in other_users:
|
||||||
|
+ with pytest.raises(SSHException):
|
||||||
|
+ print('trying to connect as {} with key from {}'.format(
|
||||||
|
+ other_user, user))
|
||||||
|
+ ssh.connect(
|
||||||
|
+ client.instance.ip,
|
||||||
|
+ username=other_user,
|
||||||
|
+ pkey=paramiko_key,
|
||||||
|
+ look_for_keys=False,
|
||||||
|
+ allow_agent=False,
|
||||||
|
+ )
|
||||||
|
diff --git a/tests/unittests/test_sshutil.py b/tests/unittests/test_sshutil.py
|
||||||
|
index fd1d1bac..bcb8044f 100644
|
||||||
|
--- a/tests/unittests/test_sshutil.py
|
||||||
|
+++ b/tests/unittests/test_sshutil.py
|
||||||
|
@@ -570,20 +570,33 @@ class TestBasicAuthorizedKeyParse(test_helpers.CiTestCase):
|
||||||
|
ssh_util.render_authorizedkeysfile_paths(
|
||||||
|
"%h/.keys", "/homedirs/bobby", "bobby"))
|
||||||
|
|
||||||
|
+ def test_all(self):
|
||||||
|
+ self.assertEqual(
|
||||||
|
+ ["/homedirs/bobby/.keys", "/homedirs/bobby/.secret/keys",
|
||||||
|
+ "/keys/path1", "/opt/bobby/keys"],
|
||||||
|
+ ssh_util.render_authorizedkeysfile_paths(
|
||||||
|
+ "%h/.keys .secret/keys /keys/path1 /opt/%u/keys",
|
||||||
|
+ "/homedirs/bobby", "bobby"))
|
||||||
|
+
|
||||||
|
|
||||||
|
class TestMultipleSshAuthorizedKeysFile(test_helpers.CiTestCase):
|
||||||
|
|
||||||
|
@patch("cloudinit.ssh_util.pwd.getpwnam")
|
||||||
|
def test_multiple_authorizedkeys_file_order1(self, m_getpwnam):
|
||||||
|
- fpw = FakePwEnt(pw_name='bobby', pw_dir='/home2/bobby')
|
||||||
|
+ fpw = FakePwEnt(pw_name='bobby', pw_dir='/tmp/home2/bobby')
|
||||||
|
m_getpwnam.return_value = fpw
|
||||||
|
- authorized_keys = self.tmp_path('authorized_keys')
|
||||||
|
+ user_ssh_folder = "%s/.ssh" % fpw.pw_dir
|
||||||
|
+
|
||||||
|
+ # /tmp/home2/bobby/.ssh/authorized_keys = rsa
|
||||||
|
+ authorized_keys = self.tmp_path('authorized_keys', dir=user_ssh_folder)
|
||||||
|
util.write_file(authorized_keys, VALID_CONTENT['rsa'])
|
||||||
|
|
||||||
|
- user_keys = self.tmp_path('user_keys')
|
||||||
|
+ # /tmp/home2/bobby/.ssh/user_keys = dsa
|
||||||
|
+ user_keys = self.tmp_path('user_keys', dir=user_ssh_folder)
|
||||||
|
util.write_file(user_keys, VALID_CONTENT['dsa'])
|
||||||
|
|
||||||
|
- sshd_config = self.tmp_path('sshd_config')
|
||||||
|
+ # /tmp/sshd_config
|
||||||
|
+ sshd_config = self.tmp_path('sshd_config', dir="/tmp")
|
||||||
|
util.write_file(
|
||||||
|
sshd_config,
|
||||||
|
"AuthorizedKeysFile %s %s" % (authorized_keys, user_keys)
|
||||||
|
@@ -593,33 +606,244 @@ class TestMultipleSshAuthorizedKeysFile(test_helpers.CiTestCase):
|
||||||
|
fpw.pw_name, sshd_config)
|
||||||
|
content = ssh_util.update_authorized_keys(auth_key_entries, [])
|
||||||
|
|
||||||
|
- self.assertEqual("%s/.ssh/authorized_keys" % fpw.pw_dir, auth_key_fn)
|
||||||
|
+ self.assertEqual(user_keys, auth_key_fn)
|
||||||
|
self.assertTrue(VALID_CONTENT['rsa'] in content)
|
||||||
|
self.assertTrue(VALID_CONTENT['dsa'] in content)
|
||||||
|
|
||||||
|
@patch("cloudinit.ssh_util.pwd.getpwnam")
|
||||||
|
def test_multiple_authorizedkeys_file_order2(self, m_getpwnam):
|
||||||
|
- fpw = FakePwEnt(pw_name='suzie', pw_dir='/home/suzie')
|
||||||
|
+ fpw = FakePwEnt(pw_name='suzie', pw_dir='/tmp/home/suzie')
|
||||||
|
m_getpwnam.return_value = fpw
|
||||||
|
- authorized_keys = self.tmp_path('authorized_keys')
|
||||||
|
+ user_ssh_folder = "%s/.ssh" % fpw.pw_dir
|
||||||
|
+
|
||||||
|
+ # /tmp/home/suzie/.ssh/authorized_keys = rsa
|
||||||
|
+ authorized_keys = self.tmp_path('authorized_keys', dir=user_ssh_folder)
|
||||||
|
util.write_file(authorized_keys, VALID_CONTENT['rsa'])
|
||||||
|
|
||||||
|
- user_keys = self.tmp_path('user_keys')
|
||||||
|
+ # /tmp/home/suzie/.ssh/user_keys = dsa
|
||||||
|
+ user_keys = self.tmp_path('user_keys', dir=user_ssh_folder)
|
||||||
|
util.write_file(user_keys, VALID_CONTENT['dsa'])
|
||||||
|
|
||||||
|
- sshd_config = self.tmp_path('sshd_config')
|
||||||
|
+ # /tmp/sshd_config
|
||||||
|
+ sshd_config = self.tmp_path('sshd_config', dir="/tmp")
|
||||||
|
util.write_file(
|
||||||
|
sshd_config,
|
||||||
|
- "AuthorizedKeysFile %s %s" % (authorized_keys, user_keys)
|
||||||
|
+ "AuthorizedKeysFile %s %s" % (user_keys, authorized_keys)
|
||||||
|
)
|
||||||
|
|
||||||
|
(auth_key_fn, auth_key_entries) = ssh_util.extract_authorized_keys(
|
||||||
|
- fpw.pw_name, sshd_config
|
||||||
|
+ fpw.pw_name, sshd_config)
|
||||||
|
+ content = ssh_util.update_authorized_keys(auth_key_entries, [])
|
||||||
|
+
|
||||||
|
+ self.assertEqual(authorized_keys, auth_key_fn)
|
||||||
|
+ self.assertTrue(VALID_CONTENT['rsa'] in content)
|
||||||
|
+ self.assertTrue(VALID_CONTENT['dsa'] in content)
|
||||||
|
+
|
||||||
|
+ @patch("cloudinit.ssh_util.pwd.getpwnam")
|
||||||
|
+ def test_multiple_authorizedkeys_file_local_global(self, m_getpwnam):
|
||||||
|
+ fpw = FakePwEnt(pw_name='bobby', pw_dir='/tmp/home2/bobby')
|
||||||
|
+ m_getpwnam.return_value = fpw
|
||||||
|
+ user_ssh_folder = "%s/.ssh" % fpw.pw_dir
|
||||||
|
+
|
||||||
|
+ # /tmp/home2/bobby/.ssh/authorized_keys = rsa
|
||||||
|
+ authorized_keys = self.tmp_path('authorized_keys', dir=user_ssh_folder)
|
||||||
|
+ util.write_file(authorized_keys, VALID_CONTENT['rsa'])
|
||||||
|
+
|
||||||
|
+ # /tmp/home2/bobby/.ssh/user_keys = dsa
|
||||||
|
+ user_keys = self.tmp_path('user_keys', dir=user_ssh_folder)
|
||||||
|
+ util.write_file(user_keys, VALID_CONTENT['dsa'])
|
||||||
|
+
|
||||||
|
+ # /tmp/etc/ssh/authorized_keys = ecdsa
|
||||||
|
+ authorized_keys_global = self.tmp_path('etc/ssh/authorized_keys',
|
||||||
|
+ dir="/tmp")
|
||||||
|
+ util.write_file(authorized_keys_global, VALID_CONTENT['ecdsa'])
|
||||||
|
+
|
||||||
|
+ # /tmp/sshd_config
|
||||||
|
+ sshd_config = self.tmp_path('sshd_config', dir="/tmp")
|
||||||
|
+ util.write_file(
|
||||||
|
+ sshd_config,
|
||||||
|
+ "AuthorizedKeysFile %s %s %s" % (authorized_keys_global,
|
||||||
|
+ user_keys, authorized_keys)
|
||||||
|
+ )
|
||||||
|
+
|
||||||
|
+ (auth_key_fn, auth_key_entries) = ssh_util.extract_authorized_keys(
|
||||||
|
+ fpw.pw_name, sshd_config)
|
||||||
|
+ content = ssh_util.update_authorized_keys(auth_key_entries, [])
|
||||||
|
+
|
||||||
|
+ self.assertEqual(authorized_keys, auth_key_fn)
|
||||||
|
+ self.assertTrue(VALID_CONTENT['rsa'] in content)
|
||||||
|
+ self.assertTrue(VALID_CONTENT['ecdsa'] in content)
|
||||||
|
+ self.assertTrue(VALID_CONTENT['dsa'] in content)
|
||||||
|
+
|
||||||
|
+ @patch("cloudinit.ssh_util.pwd.getpwnam")
|
||||||
|
+ def test_multiple_authorizedkeys_file_local_global2(self, m_getpwnam):
|
||||||
|
+ fpw = FakePwEnt(pw_name='bobby', pw_dir='/tmp/home2/bobby')
|
||||||
|
+ m_getpwnam.return_value = fpw
|
||||||
|
+ user_ssh_folder = "%s/.ssh" % fpw.pw_dir
|
||||||
|
+
|
||||||
|
+ # /tmp/home2/bobby/.ssh/authorized_keys2 = rsa
|
||||||
|
+ authorized_keys = self.tmp_path('authorized_keys2',
|
||||||
|
+ dir=user_ssh_folder)
|
||||||
|
+ util.write_file(authorized_keys, VALID_CONTENT['rsa'])
|
||||||
|
+
|
||||||
|
+ # /tmp/home2/bobby/.ssh/user_keys3 = dsa
|
||||||
|
+ user_keys = self.tmp_path('user_keys3', dir=user_ssh_folder)
|
||||||
|
+ util.write_file(user_keys, VALID_CONTENT['dsa'])
|
||||||
|
+
|
||||||
|
+ # /tmp/etc/ssh/authorized_keys = ecdsa
|
||||||
|
+ authorized_keys_global = self.tmp_path('etc/ssh/authorized_keys',
|
||||||
|
+ dir="/tmp")
|
||||||
|
+ util.write_file(authorized_keys_global, VALID_CONTENT['ecdsa'])
|
||||||
|
+
|
||||||
|
+ # /tmp/sshd_config
|
||||||
|
+ sshd_config = self.tmp_path('sshd_config', dir="/tmp")
|
||||||
|
+ util.write_file(
|
||||||
|
+ sshd_config,
|
||||||
|
+ "AuthorizedKeysFile %s %s %s" % (authorized_keys_global,
|
||||||
|
+ authorized_keys, user_keys)
|
||||||
|
+ )
|
||||||
|
+
|
||||||
|
+ (auth_key_fn, auth_key_entries) = ssh_util.extract_authorized_keys(
|
||||||
|
+ fpw.pw_name, sshd_config)
|
||||||
|
+ content = ssh_util.update_authorized_keys(auth_key_entries, [])
|
||||||
|
+
|
||||||
|
+ self.assertEqual(user_keys, auth_key_fn)
|
||||||
|
+ self.assertTrue(VALID_CONTENT['rsa'] in content)
|
||||||
|
+ self.assertTrue(VALID_CONTENT['ecdsa'] in content)
|
||||||
|
+ self.assertTrue(VALID_CONTENT['dsa'] in content)
|
||||||
|
+
|
||||||
|
+ @patch("cloudinit.ssh_util.pwd.getpwnam")
|
||||||
|
+ def test_multiple_authorizedkeys_file_global(self, m_getpwnam):
|
||||||
|
+ fpw = FakePwEnt(pw_name='bobby', pw_dir='/tmp/home2/bobby')
|
||||||
|
+ m_getpwnam.return_value = fpw
|
||||||
|
+
|
||||||
|
+ # /tmp/etc/ssh/authorized_keys = rsa
|
||||||
|
+ authorized_keys_global = self.tmp_path('etc/ssh/authorized_keys',
|
||||||
|
+ dir="/tmp")
|
||||||
|
+ util.write_file(authorized_keys_global, VALID_CONTENT['rsa'])
|
||||||
|
+
|
||||||
|
+ # /tmp/sshd_config
|
||||||
|
+ sshd_config = self.tmp_path('sshd_config')
|
||||||
|
+ util.write_file(
|
||||||
|
+ sshd_config,
|
||||||
|
+ "AuthorizedKeysFile %s" % (authorized_keys_global)
|
||||||
|
)
|
||||||
|
+
|
||||||
|
+ (auth_key_fn, auth_key_entries) = ssh_util.extract_authorized_keys(
|
||||||
|
+ fpw.pw_name, sshd_config)
|
||||||
|
content = ssh_util.update_authorized_keys(auth_key_entries, [])
|
||||||
|
|
||||||
|
self.assertEqual("%s/.ssh/authorized_keys" % fpw.pw_dir, auth_key_fn)
|
||||||
|
self.assertTrue(VALID_CONTENT['rsa'] in content)
|
||||||
|
+
|
||||||
|
+ @patch("cloudinit.ssh_util.pwd.getpwnam")
|
||||||
|
+ def test_multiple_authorizedkeys_file_multiuser(self, m_getpwnam):
|
||||||
|
+ fpw = FakePwEnt(pw_name='bobby', pw_dir='/tmp/home2/bobby')
|
||||||
|
+ m_getpwnam.return_value = fpw
|
||||||
|
+ user_ssh_folder = "%s/.ssh" % fpw.pw_dir
|
||||||
|
+ # /tmp/home2/bobby/.ssh/authorized_keys2 = rsa
|
||||||
|
+ authorized_keys = self.tmp_path('authorized_keys2',
|
||||||
|
+ dir=user_ssh_folder)
|
||||||
|
+ util.write_file(authorized_keys, VALID_CONTENT['rsa'])
|
||||||
|
+ # /tmp/home2/bobby/.ssh/user_keys3 = dsa
|
||||||
|
+ user_keys = self.tmp_path('user_keys3', dir=user_ssh_folder)
|
||||||
|
+ util.write_file(user_keys, VALID_CONTENT['dsa'])
|
||||||
|
+
|
||||||
|
+ fpw2 = FakePwEnt(pw_name='suzie', pw_dir='/tmp/home/suzie')
|
||||||
|
+ user_ssh_folder = "%s/.ssh" % fpw2.pw_dir
|
||||||
|
+ # /tmp/home/suzie/.ssh/authorized_keys2 = ssh-xmss@openssh.com
|
||||||
|
+ authorized_keys2 = self.tmp_path('authorized_keys2',
|
||||||
|
+ dir=user_ssh_folder)
|
||||||
|
+ util.write_file(authorized_keys2,
|
||||||
|
+ VALID_CONTENT['ssh-xmss@openssh.com'])
|
||||||
|
+
|
||||||
|
+ # /tmp/etc/ssh/authorized_keys = ecdsa
|
||||||
|
+ authorized_keys_global = self.tmp_path('etc/ssh/authorized_keys2',
|
||||||
|
+ dir="/tmp")
|
||||||
|
+ util.write_file(authorized_keys_global, VALID_CONTENT['ecdsa'])
|
||||||
|
+
|
||||||
|
+ # /tmp/sshd_config
|
||||||
|
+ sshd_config = self.tmp_path('sshd_config', dir="/tmp")
|
||||||
|
+ util.write_file(
|
||||||
|
+ sshd_config,
|
||||||
|
+ "AuthorizedKeysFile %s %%h/.ssh/authorized_keys2 %s" %
|
||||||
|
+ (authorized_keys_global, user_keys)
|
||||||
|
+ )
|
||||||
|
+
|
||||||
|
+ # process first user
|
||||||
|
+ (auth_key_fn, auth_key_entries) = ssh_util.extract_authorized_keys(
|
||||||
|
+ fpw.pw_name, sshd_config)
|
||||||
|
+ content = ssh_util.update_authorized_keys(auth_key_entries, [])
|
||||||
|
+
|
||||||
|
+ self.assertEqual(user_keys, auth_key_fn)
|
||||||
|
+ self.assertTrue(VALID_CONTENT['rsa'] in content)
|
||||||
|
+ self.assertTrue(VALID_CONTENT['ecdsa'] in content)
|
||||||
|
+ self.assertTrue(VALID_CONTENT['dsa'] in content)
|
||||||
|
+ self.assertFalse(VALID_CONTENT['ssh-xmss@openssh.com'] in content)
|
||||||
|
+
|
||||||
|
+ m_getpwnam.return_value = fpw2
|
||||||
|
+ # process second user
|
||||||
|
+ (auth_key_fn, auth_key_entries) = ssh_util.extract_authorized_keys(
|
||||||
|
+ fpw2.pw_name, sshd_config)
|
||||||
|
+ content = ssh_util.update_authorized_keys(auth_key_entries, [])
|
||||||
|
+
|
||||||
|
+ self.assertEqual(authorized_keys2, auth_key_fn)
|
||||||
|
+ self.assertTrue(VALID_CONTENT['ssh-xmss@openssh.com'] in content)
|
||||||
|
+ self.assertTrue(VALID_CONTENT['ecdsa'] in content)
|
||||||
|
+ self.assertTrue(VALID_CONTENT['dsa'] in content)
|
||||||
|
+ self.assertFalse(VALID_CONTENT['rsa'] in content)
|
||||||
|
+
|
||||||
|
+ @patch("cloudinit.ssh_util.pwd.getpwnam")
|
||||||
|
+ def test_multiple_authorizedkeys_file_multiuser2(self, m_getpwnam):
|
||||||
|
+ fpw = FakePwEnt(pw_name='bobby', pw_dir='/tmp/home/bobby')
|
||||||
|
+ m_getpwnam.return_value = fpw
|
||||||
|
+ user_ssh_folder = "%s/.ssh" % fpw.pw_dir
|
||||||
|
+ # /tmp/home/bobby/.ssh/authorized_keys2 = rsa
|
||||||
|
+ authorized_keys = self.tmp_path('authorized_keys2',
|
||||||
|
+ dir=user_ssh_folder)
|
||||||
|
+ util.write_file(authorized_keys, VALID_CONTENT['rsa'])
|
||||||
|
+ # /tmp/home/bobby/.ssh/user_keys3 = dsa
|
||||||
|
+ user_keys = self.tmp_path('user_keys3', dir=user_ssh_folder)
|
||||||
|
+ util.write_file(user_keys, VALID_CONTENT['dsa'])
|
||||||
|
+
|
||||||
|
+ fpw2 = FakePwEnt(pw_name='badguy', pw_dir='/tmp/home/badguy')
|
||||||
|
+ user_ssh_folder = "%s/.ssh" % fpw2.pw_dir
|
||||||
|
+ # /tmp/home/badguy/home/bobby = ""
|
||||||
|
+ authorized_keys2 = self.tmp_path('home/bobby', dir="/tmp/home/badguy")
|
||||||
|
+
|
||||||
|
+ # /tmp/etc/ssh/authorized_keys = ecdsa
|
||||||
|
+ authorized_keys_global = self.tmp_path('etc/ssh/authorized_keys2',
|
||||||
|
+ dir="/tmp")
|
||||||
|
+ util.write_file(authorized_keys_global, VALID_CONTENT['ecdsa'])
|
||||||
|
+
|
||||||
|
+ # /tmp/sshd_config
|
||||||
|
+ sshd_config = self.tmp_path('sshd_config', dir="/tmp")
|
||||||
|
+ util.write_file(
|
||||||
|
+ sshd_config,
|
||||||
|
+ "AuthorizedKeysFile %s %%h/.ssh/authorized_keys2 %s %s" %
|
||||||
|
+ (authorized_keys_global, user_keys, authorized_keys2)
|
||||||
|
+ )
|
||||||
|
+
|
||||||
|
+ # process first user
|
||||||
|
+ (auth_key_fn, auth_key_entries) = ssh_util.extract_authorized_keys(
|
||||||
|
+ fpw.pw_name, sshd_config)
|
||||||
|
+ content = ssh_util.update_authorized_keys(auth_key_entries, [])
|
||||||
|
+
|
||||||
|
+ self.assertEqual(user_keys, auth_key_fn)
|
||||||
|
+ self.assertTrue(VALID_CONTENT['rsa'] in content)
|
||||||
|
+ self.assertTrue(VALID_CONTENT['ecdsa'] in content)
|
||||||
|
+ self.assertTrue(VALID_CONTENT['dsa'] in content)
|
||||||
|
+
|
||||||
|
+ m_getpwnam.return_value = fpw2
|
||||||
|
+ # process second user
|
||||||
|
+ (auth_key_fn, auth_key_entries) = ssh_util.extract_authorized_keys(
|
||||||
|
+ fpw2.pw_name, sshd_config)
|
||||||
|
+ content = ssh_util.update_authorized_keys(auth_key_entries, [])
|
||||||
|
+
|
||||||
|
+ # badguy should not take the key from the other user!
|
||||||
|
+ self.assertEqual(authorized_keys2, auth_key_fn)
|
||||||
|
+ self.assertTrue(VALID_CONTENT['ecdsa'] in content)
|
||||||
|
self.assertTrue(VALID_CONTENT['dsa'] in content)
|
||||||
|
+ self.assertFalse(VALID_CONTENT['rsa'] in content)
|
||||||
|
|
||||||
|
# vi: ts=4 expandtab
|
||||||
|
--
|
||||||
|
2.27.0
|
||||||
|
|
@ -0,0 +1,371 @@
|
|||||||
|
From f9564bd4477782e8cffe4be1d3c31c0338fb03b1 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Eduardo Otubo <otubo@redhat.com>
|
||||||
|
Date: Mon, 5 Jul 2021 14:07:21 +0200
|
||||||
|
Subject: [PATCH 1/2] write passwords only to serial console, lock down
|
||||||
|
cloud-init-output.log (#847)
|
||||||
|
|
||||||
|
RH-Author: Eduardo Otubo <otubo@redhat.com>
|
||||||
|
RH-MergeRequest: 4: write passwords only to serial console, lock down cloud-init-output.log (#847)
|
||||||
|
RH-Commit: [1/1] 7543b3458c01ea988e987336d84510157c00390d (otubo/cloud-init-src)
|
||||||
|
RH-Bugzilla: 1945892
|
||||||
|
RH-Acked-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
|
||||||
|
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||||
|
RH-Acked-by: Mohamed Gamal Morsy <mmorsy@redhat.com>
|
||||||
|
|
||||||
|
commit b794d426b9ab43ea9d6371477466070d86e10668
|
||||||
|
Author: Daniel Watkins <oddbloke@ubuntu.com>
|
||||||
|
Date: Fri Mar 19 10:06:42 2021 -0400
|
||||||
|
|
||||||
|
write passwords only to serial console, lock down cloud-init-output.log (#847)
|
||||||
|
|
||||||
|
Prior to this commit, when a user specified configuration which would
|
||||||
|
generate random passwords for users, cloud-init would cause those
|
||||||
|
passwords to be written to the serial console by emitting them on
|
||||||
|
stderr. In the default configuration, any stdout or stderr emitted by
|
||||||
|
cloud-init is also written to `/var/log/cloud-init-output.log`. This
|
||||||
|
file is world-readable, meaning that those randomly-generated passwords
|
||||||
|
were available to be read by any user with access to the system. This
|
||||||
|
presents an obvious security issue.
|
||||||
|
|
||||||
|
This commit responds to this issue in two ways:
|
||||||
|
|
||||||
|
* We address the direct issue by moving from writing the passwords to
|
||||||
|
sys.stderr to writing them directly to /dev/console (via
|
||||||
|
util.multi_log); this means that the passwords will never end up in
|
||||||
|
cloud-init-output.log
|
||||||
|
* To avoid future issues like this, we also modify the logging code so
|
||||||
|
that any files created in a log sink subprocess will only be
|
||||||
|
owner/group readable and, if it exists, will be owned by the adm
|
||||||
|
group. This results in `/var/log/cloud-init-output.log` no longer
|
||||||
|
being world-readable, meaning that if there are other parts of the
|
||||||
|
codebase that are emitting sensitive data intended for the serial
|
||||||
|
console, that data is no longer available to all users of the system.
|
||||||
|
|
||||||
|
LP: #1918303
|
||||||
|
|
||||||
|
Signed-off-by: Eduardo Otubo <otubo@redhat.com>
|
||||||
|
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
|
||||||
|
---
|
||||||
|
cloudinit/config/cc_set_passwords.py | 5 +-
|
||||||
|
cloudinit/config/tests/test_set_passwords.py | 40 +++++++++----
|
||||||
|
cloudinit/tests/test_util.py | 56 +++++++++++++++++++
|
||||||
|
cloudinit/util.py | 38 +++++++++++--
|
||||||
|
.../modules/test_set_password.py | 24 ++++++++
|
||||||
|
tests/integration_tests/test_logging.py | 22 ++++++++
|
||||||
|
tests/unittests/test_util.py | 4 ++
|
||||||
|
7 files changed, 173 insertions(+), 16 deletions(-)
|
||||||
|
create mode 100644 tests/integration_tests/test_logging.py
|
||||||
|
|
||||||
|
diff --git a/cloudinit/config/cc_set_passwords.py b/cloudinit/config/cc_set_passwords.py
|
||||||
|
index d6b5682d..433de751 100755
|
||||||
|
--- a/cloudinit/config/cc_set_passwords.py
|
||||||
|
+++ b/cloudinit/config/cc_set_passwords.py
|
||||||
|
@@ -78,7 +78,6 @@ password.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import re
|
||||||
|
-import sys
|
||||||
|
|
||||||
|
from cloudinit.distros import ug_util
|
||||||
|
from cloudinit import log as logging
|
||||||
|
@@ -214,7 +213,9 @@ def handle(_name, cfg, cloud, log, args):
|
||||||
|
if len(randlist):
|
||||||
|
blurb = ("Set the following 'random' passwords\n",
|
||||||
|
'\n'.join(randlist))
|
||||||
|
- sys.stderr.write("%s\n%s\n" % blurb)
|
||||||
|
+ util.multi_log(
|
||||||
|
+ "%s\n%s\n" % blurb, stderr=False, fallback_to_stdout=False
|
||||||
|
+ )
|
||||||
|
|
||||||
|
if expire:
|
||||||
|
expired_users = []
|
||||||
|
diff --git a/cloudinit/config/tests/test_set_passwords.py b/cloudinit/config/tests/test_set_passwords.py
|
||||||
|
index daa1ef51..bbe2ee8f 100644
|
||||||
|
--- a/cloudinit/config/tests/test_set_passwords.py
|
||||||
|
+++ b/cloudinit/config/tests/test_set_passwords.py
|
||||||
|
@@ -74,10 +74,6 @@ class TestSetPasswordsHandle(CiTestCase):
|
||||||
|
|
||||||
|
with_logs = True
|
||||||
|
|
||||||
|
- def setUp(self):
|
||||||
|
- super(TestSetPasswordsHandle, self).setUp()
|
||||||
|
- self.add_patch('cloudinit.config.cc_set_passwords.sys.stderr', 'm_err')
|
||||||
|
-
|
||||||
|
def test_handle_on_empty_config(self, *args):
|
||||||
|
"""handle logs that no password has changed when config is empty."""
|
||||||
|
cloud = self.tmp_cloud(distro='ubuntu')
|
||||||
|
@@ -129,10 +125,12 @@ class TestSetPasswordsHandle(CiTestCase):
|
||||||
|
mock.call(['pw', 'usermod', 'ubuntu', '-p', '01-Jan-1970'])],
|
||||||
|
m_subp.call_args_list)
|
||||||
|
|
||||||
|
+ @mock.patch(MODPATH + "util.multi_log")
|
||||||
|
@mock.patch(MODPATH + "util.is_BSD")
|
||||||
|
@mock.patch(MODPATH + "subp.subp")
|
||||||
|
- def test_handle_on_chpasswd_list_creates_random_passwords(self, m_subp,
|
||||||
|
- m_is_bsd):
|
||||||
|
+ def test_handle_on_chpasswd_list_creates_random_passwords(
|
||||||
|
+ self, m_subp, m_is_bsd, m_multi_log
|
||||||
|
+ ):
|
||||||
|
"""handle parses command set random passwords."""
|
||||||
|
m_is_bsd.return_value = False
|
||||||
|
cloud = self.tmp_cloud(distro='ubuntu')
|
||||||
|
@@ -146,10 +144,32 @@ class TestSetPasswordsHandle(CiTestCase):
|
||||||
|
self.assertIn(
|
||||||
|
'DEBUG: Handling input for chpasswd as list.',
|
||||||
|
self.logs.getvalue())
|
||||||
|
- self.assertNotEqual(
|
||||||
|
- [mock.call(['chpasswd'],
|
||||||
|
- '\n'.join(valid_random_pwds) + '\n')],
|
||||||
|
- m_subp.call_args_list)
|
||||||
|
+
|
||||||
|
+ self.assertEqual(1, m_subp.call_count)
|
||||||
|
+ args, _kwargs = m_subp.call_args
|
||||||
|
+ self.assertEqual(["chpasswd"], args[0])
|
||||||
|
+
|
||||||
|
+ stdin = args[1]
|
||||||
|
+ user_pass = {
|
||||||
|
+ user: password
|
||||||
|
+ for user, password
|
||||||
|
+ in (line.split(":") for line in stdin.splitlines())
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ self.assertEqual(1, m_multi_log.call_count)
|
||||||
|
+ self.assertEqual(
|
||||||
|
+ mock.call(mock.ANY, stderr=False, fallback_to_stdout=False),
|
||||||
|
+ m_multi_log.call_args
|
||||||
|
+ )
|
||||||
|
+
|
||||||
|
+ self.assertEqual(set(["root", "ubuntu"]), set(user_pass.keys()))
|
||||||
|
+ written_lines = m_multi_log.call_args[0][0].splitlines()
|
||||||
|
+ for password in user_pass.values():
|
||||||
|
+ for line in written_lines:
|
||||||
|
+ if password in line:
|
||||||
|
+ break
|
||||||
|
+ else:
|
||||||
|
+ self.fail("Password not emitted to console")
|
||||||
|
|
||||||
|
|
||||||
|
# vi: ts=4 expandtab
|
||||||
|
diff --git a/cloudinit/tests/test_util.py b/cloudinit/tests/test_util.py
|
||||||
|
index b7a302f1..e811917e 100644
|
||||||
|
--- a/cloudinit/tests/test_util.py
|
||||||
|
+++ b/cloudinit/tests/test_util.py
|
||||||
|
@@ -851,4 +851,60 @@ class TestEnsureFile:
|
||||||
|
assert "ab" == kwargs["omode"]
|
||||||
|
|
||||||
|
|
||||||
|
+@mock.patch("cloudinit.util.grp.getgrnam")
|
||||||
|
+@mock.patch("cloudinit.util.os.setgid")
|
||||||
|
+@mock.patch("cloudinit.util.os.umask")
|
||||||
|
+class TestRedirectOutputPreexecFn:
|
||||||
|
+ """This tests specifically the preexec_fn used in redirect_output."""
|
||||||
|
+
|
||||||
|
+ @pytest.fixture(params=["outfmt", "errfmt"])
|
||||||
|
+ def preexec_fn(self, request):
|
||||||
|
+ """A fixture to gather the preexec_fn used by redirect_output.
|
||||||
|
+
|
||||||
|
+ This enables simpler direct testing of it, and parameterises any tests
|
||||||
|
+ using it to cover both the stdout and stderr code paths.
|
||||||
|
+ """
|
||||||
|
+ test_string = "| piped output to invoke subprocess"
|
||||||
|
+ if request.param == "outfmt":
|
||||||
|
+ args = (test_string, None)
|
||||||
|
+ elif request.param == "errfmt":
|
||||||
|
+ args = (None, test_string)
|
||||||
|
+ with mock.patch("cloudinit.util.subprocess.Popen") as m_popen:
|
||||||
|
+ util.redirect_output(*args)
|
||||||
|
+
|
||||||
|
+ assert 1 == m_popen.call_count
|
||||||
|
+ _args, kwargs = m_popen.call_args
|
||||||
|
+ assert "preexec_fn" in kwargs, "preexec_fn not passed to Popen"
|
||||||
|
+ return kwargs["preexec_fn"]
|
||||||
|
+
|
||||||
|
+ def test_preexec_fn_sets_umask(
|
||||||
|
+ self, m_os_umask, _m_setgid, _m_getgrnam, preexec_fn
|
||||||
|
+ ):
|
||||||
|
+ """preexec_fn should set a mask that avoids world-readable files."""
|
||||||
|
+ preexec_fn()
|
||||||
|
+
|
||||||
|
+ assert [mock.call(0o037)] == m_os_umask.call_args_list
|
||||||
|
+
|
||||||
|
+ def test_preexec_fn_sets_group_id_if_adm_group_present(
|
||||||
|
+ self, _m_os_umask, m_setgid, m_getgrnam, preexec_fn
|
||||||
|
+ ):
|
||||||
|
+ """We should setgrp to adm if present, so files are owned by them."""
|
||||||
|
+ fake_group = mock.Mock(gr_gid=mock.sentinel.gr_gid)
|
||||||
|
+ m_getgrnam.return_value = fake_group
|
||||||
|
+
|
||||||
|
+ preexec_fn()
|
||||||
|
+
|
||||||
|
+ assert [mock.call("adm")] == m_getgrnam.call_args_list
|
||||||
|
+ assert [mock.call(mock.sentinel.gr_gid)] == m_setgid.call_args_list
|
||||||
|
+
|
||||||
|
+ def test_preexec_fn_handles_absent_adm_group_gracefully(
|
||||||
|
+ self, _m_os_umask, m_setgid, m_getgrnam, preexec_fn
|
||||||
|
+ ):
|
||||||
|
+ """We should handle an absent adm group gracefully."""
|
||||||
|
+ m_getgrnam.side_effect = KeyError("getgrnam(): name not found: 'adm'")
|
||||||
|
+
|
||||||
|
+ preexec_fn()
|
||||||
|
+
|
||||||
|
+ assert 0 == m_setgid.call_count
|
||||||
|
+
|
||||||
|
# vi: ts=4 expandtab
|
||||||
|
diff --git a/cloudinit/util.py b/cloudinit/util.py
|
||||||
|
index 769f3425..4e0a72db 100644
|
||||||
|
--- a/cloudinit/util.py
|
||||||
|
+++ b/cloudinit/util.py
|
||||||
|
@@ -359,7 +359,7 @@ def find_modules(root_dir):
|
||||||
|
|
||||||
|
|
||||||
|
def multi_log(text, console=True, stderr=True,
|
||||||
|
- log=None, log_level=logging.DEBUG):
|
||||||
|
+ log=None, log_level=logging.DEBUG, fallback_to_stdout=True):
|
||||||
|
if stderr:
|
||||||
|
sys.stderr.write(text)
|
||||||
|
if console:
|
||||||
|
@@ -368,7 +368,7 @@ def multi_log(text, console=True, stderr=True,
|
||||||
|
with open(conpath, 'w') as wfh:
|
||||||
|
wfh.write(text)
|
||||||
|
wfh.flush()
|
||||||
|
- else:
|
||||||
|
+ elif fallback_to_stdout:
|
||||||
|
# A container may lack /dev/console (arguably a container bug). If
|
||||||
|
# it does not exist, then write output to stdout. this will result
|
||||||
|
# in duplicate stderr and stdout messages if stderr was True.
|
||||||
|
@@ -623,6 +623,26 @@ def redirect_output(outfmt, errfmt, o_out=None, o_err=None):
|
||||||
|
if not o_err:
|
||||||
|
o_err = sys.stderr
|
||||||
|
|
||||||
|
+ # pylint: disable=subprocess-popen-preexec-fn
|
||||||
|
+ def set_subprocess_umask_and_gid():
|
||||||
|
+ """Reconfigure umask and group ID to create output files securely.
|
||||||
|
+
|
||||||
|
+ This is passed to subprocess.Popen as preexec_fn, so it is executed in
|
||||||
|
+ the context of the newly-created process. It:
|
||||||
|
+
|
||||||
|
+ * sets the umask of the process so created files aren't world-readable
|
||||||
|
+ * if an adm group exists in the system, sets that as the process' GID
|
||||||
|
+ (so that the created file(s) are owned by root:adm)
|
||||||
|
+ """
|
||||||
|
+ os.umask(0o037)
|
||||||
|
+ try:
|
||||||
|
+ group_id = grp.getgrnam("adm").gr_gid
|
||||||
|
+ except KeyError:
|
||||||
|
+ # No adm group, don't set a group
|
||||||
|
+ pass
|
||||||
|
+ else:
|
||||||
|
+ os.setgid(group_id)
|
||||||
|
+
|
||||||
|
if outfmt:
|
||||||
|
LOG.debug("Redirecting %s to %s", o_out, outfmt)
|
||||||
|
(mode, arg) = outfmt.split(" ", 1)
|
||||||
|
@@ -632,7 +652,12 @@ def redirect_output(outfmt, errfmt, o_out=None, o_err=None):
|
||||||
|
owith = "wb"
|
||||||
|
new_fp = open(arg, owith)
|
||||||
|
elif mode == "|":
|
||||||
|
- proc = subprocess.Popen(arg, shell=True, stdin=subprocess.PIPE)
|
||||||
|
+ proc = subprocess.Popen(
|
||||||
|
+ arg,
|
||||||
|
+ shell=True,
|
||||||
|
+ stdin=subprocess.PIPE,
|
||||||
|
+ preexec_fn=set_subprocess_umask_and_gid,
|
||||||
|
+ )
|
||||||
|
new_fp = proc.stdin
|
||||||
|
else:
|
||||||
|
raise TypeError("Invalid type for output format: %s" % outfmt)
|
||||||
|
@@ -654,7 +679,12 @@ def redirect_output(outfmt, errfmt, o_out=None, o_err=None):
|
||||||
|
owith = "wb"
|
||||||
|
new_fp = open(arg, owith)
|
||||||
|
elif mode == "|":
|
||||||
|
- proc = subprocess.Popen(arg, shell=True, stdin=subprocess.PIPE)
|
||||||
|
+ proc = subprocess.Popen(
|
||||||
|
+ arg,
|
||||||
|
+ shell=True,
|
||||||
|
+ stdin=subprocess.PIPE,
|
||||||
|
+ preexec_fn=set_subprocess_umask_and_gid,
|
||||||
|
+ )
|
||||||
|
new_fp = proc.stdin
|
||||||
|
else:
|
||||||
|
raise TypeError("Invalid type for error format: %s" % errfmt)
|
||||||
|
diff --git a/tests/integration_tests/modules/test_set_password.py b/tests/integration_tests/modules/test_set_password.py
|
||||||
|
index b13f76fb..d7cf91a5 100644
|
||||||
|
--- a/tests/integration_tests/modules/test_set_password.py
|
||||||
|
+++ b/tests/integration_tests/modules/test_set_password.py
|
||||||
|
@@ -116,6 +116,30 @@ class Mixin:
|
||||||
|
# Which are not the same
|
||||||
|
assert shadow_users["harry"] != shadow_users["dick"]
|
||||||
|
|
||||||
|
+ def test_random_passwords_not_stored_in_cloud_init_output_log(
|
||||||
|
+ self, class_client
|
||||||
|
+ ):
|
||||||
|
+ """We should not emit passwords to the in-instance log file.
|
||||||
|
+
|
||||||
|
+ LP: #1918303
|
||||||
|
+ """
|
||||||
|
+ cloud_init_output = class_client.read_from_file(
|
||||||
|
+ "/var/log/cloud-init-output.log"
|
||||||
|
+ )
|
||||||
|
+ assert "dick:" not in cloud_init_output
|
||||||
|
+ assert "harry:" not in cloud_init_output
|
||||||
|
+
|
||||||
|
+ def test_random_passwords_emitted_to_serial_console(self, class_client):
|
||||||
|
+ """We should emit passwords to the serial console. (LP: #1918303)"""
|
||||||
|
+ try:
|
||||||
|
+ console_log = class_client.instance.console_log()
|
||||||
|
+ except NotImplementedError:
|
||||||
|
+ # Assume that an exception here means that we can't use the console
|
||||||
|
+ # log
|
||||||
|
+ pytest.skip("NotImplementedError when requesting console log")
|
||||||
|
+ assert "dick:" in console_log
|
||||||
|
+ assert "harry:" in console_log
|
||||||
|
+
|
||||||
|
def test_explicit_password_set_correctly(self, class_client):
|
||||||
|
"""Test that an explicitly-specified password is set correctly."""
|
||||||
|
shadow_users, _ = self._fetch_and_parse_etc_shadow(class_client)
|
||||||
|
diff --git a/tests/integration_tests/test_logging.py b/tests/integration_tests/test_logging.py
|
||||||
|
new file mode 100644
|
||||||
|
index 00000000..b31a0434
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/tests/integration_tests/test_logging.py
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+"""Integration tests relating to cloud-init's logging."""
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+class TestVarLogCloudInitOutput:
|
||||||
|
+ """Integration tests relating to /var/log/cloud-init-output.log."""
|
||||||
|
+
|
||||||
|
+ def test_var_log_cloud_init_output_not_world_readable(self, client):
|
||||||
|
+ """
|
||||||
|
+ The log can contain sensitive data, it shouldn't be world-readable.
|
||||||
|
+
|
||||||
|
+ LP: #1918303
|
||||||
|
+ """
|
||||||
|
+ # Check the file exists
|
||||||
|
+ assert client.execute("test -f /var/log/cloud-init-output.log").ok
|
||||||
|
+
|
||||||
|
+ # Check its permissions are as we expect
|
||||||
|
+ perms, user, group = client.execute(
|
||||||
|
+ "stat -c %a:%U:%G /var/log/cloud-init-output.log"
|
||||||
|
+ ).split(":")
|
||||||
|
+ assert "640" == perms
|
||||||
|
+ assert "root" == user
|
||||||
|
+ assert "adm" == group
|
||||||
|
diff --git a/tests/unittests/test_util.py b/tests/unittests/test_util.py
|
||||||
|
index 857629f1..e5292001 100644
|
||||||
|
--- a/tests/unittests/test_util.py
|
||||||
|
+++ b/tests/unittests/test_util.py
|
||||||
|
@@ -572,6 +572,10 @@ class TestMultiLog(helpers.FilesystemMockingTestCase):
|
||||||
|
util.multi_log(logged_string)
|
||||||
|
self.assertEqual(logged_string, self.stdout.getvalue())
|
||||||
|
|
||||||
|
+ def test_logs_dont_go_to_stdout_if_fallback_to_stdout_is_false(self):
|
||||||
|
+ util.multi_log('something', fallback_to_stdout=False)
|
||||||
|
+ self.assertEqual('', self.stdout.getvalue())
|
||||||
|
+
|
||||||
|
def test_logs_go_to_log_if_given(self):
|
||||||
|
log = mock.MagicMock()
|
||||||
|
logged_string = 'something very important'
|
||||||
|
--
|
||||||
|
2.27.0
|
||||||
|
|
1
SOURCES/cloud-init-tmpfiles.conf
Normal file
1
SOURCES/cloud-init-tmpfiles.conf
Normal file
@ -0,0 +1 @@
|
|||||||
|
d /run/cloud-init 0700 root root - -
|
438
SPECS/cloud-init.spec
Normal file
438
SPECS/cloud-init.spec
Normal file
@ -0,0 +1,438 @@
|
|||||||
|
Name: cloud-init
|
||||||
|
Version: 21.1
|
||||||
|
Release: 7%{?dist}
|
||||||
|
Summary: Cloud instance init scripts
|
||||||
|
License: ASL 2.0 or GPLv3
|
||||||
|
URL: http://launchpad.net/cloud-init
|
||||||
|
Source0: https://launchpad.net/cloud-init/trunk/%{version}/+download/%{name}-%{version}.tar.gz
|
||||||
|
Source1: cloud-init-tmpfiles.conf
|
||||||
|
|
||||||
|
Patch0001: 0001-Add-initial-redhat-setup.patch
|
||||||
|
Patch0002: 0002-Do-not-write-NM_CONTROLLED-no-in-generated-interface.patch
|
||||||
|
Patch0003: 0003-limit-permissions-on-def_log_file.patch
|
||||||
|
# For bz#1970909 - [cloud-init] From RHEL 82+ cloud-init no longer displays sshd keys fingerprints from instance launched from a backup image[rhel-9]
|
||||||
|
Patch4: ci-rhel-cloud.cfg-remove-ssh_genkeytypes-in-settings.py.patch
|
||||||
|
# For bz#1943511 - [Aliyun][RHEL9.0][cloud-init] cloud-init service failed to start with Alibaba instance
|
||||||
|
Patch5: ci-Fix-requiring-device-number-on-EC2-derivatives-836.patch
|
||||||
|
# For bz#1945892 - CVE-2021-3429 cloud-init: randomly generated passwords logged in clear-text to world-readable file [rhel-9.0]
|
||||||
|
Patch6: ci-write-passwords-only-to-serial-console-lock-down-clo.patch
|
||||||
|
# For bz#1979099 - [cloud-init]Customize ssh AuthorizedKeysFile causes login failure[RHEL-9.0]
|
||||||
|
Patch7: ci-ssh-util-allow-cloudinit-to-merge-all-ssh-keys-into-.patch
|
||||||
|
# For bz#1979099 - [cloud-init]Customize ssh AuthorizedKeysFile causes login failure[RHEL-9.0]
|
||||||
|
Patch8: ci-Stop-copying-ssh-system-keys-and-check-folder-permis.patch
|
||||||
|
|
||||||
|
# Source-git patches
|
||||||
|
|
||||||
|
BuildArch: noarch
|
||||||
|
|
||||||
|
BuildRequires: pkgconfig(systemd)
|
||||||
|
BuildRequires: python3-devel
|
||||||
|
BuildRequires: python3-setuptools
|
||||||
|
BuildRequires: systemd
|
||||||
|
|
||||||
|
# For tests
|
||||||
|
BuildRequires: iproute
|
||||||
|
BuildRequires: python3-configobj
|
||||||
|
# https://bugzilla.redhat.com/show_bug.cgi?id=1695953
|
||||||
|
BuildRequires: python3-distro
|
||||||
|
# https://bugzilla.redhat.com/show_bug.cgi?id=1417029
|
||||||
|
BuildRequires: python3-httpretty >= 0.8.14-2
|
||||||
|
BuildRequires: python3-jinja2
|
||||||
|
BuildRequires: python3-jsonpatch
|
||||||
|
BuildRequires: python3-oauthlib
|
||||||
|
BuildRequires: python3-prettytable
|
||||||
|
BuildRequires: python3-pyserial
|
||||||
|
BuildRequires: python3-PyYAML
|
||||||
|
BuildRequires: python3-requests
|
||||||
|
BuildRequires: python3-six
|
||||||
|
# dnf is needed to make cc_ntp unit tests work
|
||||||
|
# https://bugs.launchpad.net/cloud-init/+bug/1721573
|
||||||
|
BuildRequires: /usr/bin/dnf
|
||||||
|
|
||||||
|
Requires: e2fsprogs
|
||||||
|
Requires: iproute
|
||||||
|
Requires: libselinux-python3
|
||||||
|
Requires: policycoreutils-python3
|
||||||
|
Requires: procps
|
||||||
|
Requires: python3-configobj
|
||||||
|
# https://bugzilla.redhat.com/show_bug.cgi?id=1695953
|
||||||
|
Requires: python3-distro
|
||||||
|
Requires: python3-jinja2
|
||||||
|
Requires: python3-jsonpatch
|
||||||
|
Requires: python3-oauthlib
|
||||||
|
Requires: python3-prettytable
|
||||||
|
Requires: python3-pyserial
|
||||||
|
Requires: python3-PyYAML
|
||||||
|
Requires: python3-requests
|
||||||
|
Requires: python3-six
|
||||||
|
Requires: shadow-utils
|
||||||
|
Requires: util-linux
|
||||||
|
Requires: xfsprogs
|
||||||
|
Requires: dhcp-client
|
||||||
|
|
||||||
|
%{?systemd_requires}
|
||||||
|
|
||||||
|
%description
|
||||||
|
Cloud-init is a set of init scripts for cloud instances. Cloud instances
|
||||||
|
need special scripts to run during initialization to retrieve and install
|
||||||
|
ssh keys and to let the user run various scripts.
|
||||||
|
|
||||||
|
|
||||||
|
%prep
|
||||||
|
%autosetup -p1
|
||||||
|
|
||||||
|
# Change shebangs
|
||||||
|
sed -i -e 's|#!/usr/bin/env python|#!/usr/bin/env python3|' \
|
||||||
|
-e 's|#!/usr/bin/python|#!/usr/bin/python3|' tools/* cloudinit/ssh_util.py
|
||||||
|
|
||||||
|
%build
|
||||||
|
%py3_build
|
||||||
|
|
||||||
|
|
||||||
|
%install
|
||||||
|
%py3_install --
|
||||||
|
|
||||||
|
%if 0%{?fedora}
|
||||||
|
python3 tools/render-cloudcfg --variant fedora > $RPM_BUILD_ROOT/%{_sysconfdir}/cloud/cloud.cfg
|
||||||
|
%elif 0%{?rhel}
|
||||||
|
cp -p rhel/cloud.cfg $RPM_BUILD_ROOT/%{_sysconfdir}/cloud/cloud.cfg
|
||||||
|
%endif
|
||||||
|
|
||||||
|
sed -i "s,@@PACKAGED_VERSION@@,%{version}-%{release}," $RPM_BUILD_ROOT/%{python3_sitelib}/cloudinit/version.py
|
||||||
|
|
||||||
|
mkdir -p $RPM_BUILD_ROOT/var/lib/cloud
|
||||||
|
|
||||||
|
# /run/cloud-init needs a tmpfiles.d entry
|
||||||
|
mkdir -p $RPM_BUILD_ROOT/run/cloud-init
|
||||||
|
mkdir -p $RPM_BUILD_ROOT/%{_tmpfilesdir}
|
||||||
|
cp -p %{SOURCE1} $RPM_BUILD_ROOT/%{_tmpfilesdir}/%{name}.conf
|
||||||
|
|
||||||
|
# We supply our own config file since our software differs from Ubuntu's.
|
||||||
|
cp -p rhel/cloud.cfg $RPM_BUILD_ROOT/%{_sysconfdir}/cloud/cloud.cfg
|
||||||
|
|
||||||
|
mkdir -p $RPM_BUILD_ROOT/%{_sysconfdir}/rsyslog.d
|
||||||
|
cp -p tools/21-cloudinit.conf $RPM_BUILD_ROOT/%{_sysconfdir}/rsyslog.d/21-cloudinit.conf
|
||||||
|
|
||||||
|
# Make installed NetworkManager hook name less generic
|
||||||
|
mv $RPM_BUILD_ROOT/etc/NetworkManager/dispatcher.d/hook-network-manager \
|
||||||
|
$RPM_BUILD_ROOT/etc/NetworkManager/dispatcher.d/cloud-init-azure-hook
|
||||||
|
|
||||||
|
# Install our own systemd units (rhbz#1440831)
|
||||||
|
mkdir -p $RPM_BUILD_ROOT%{_unitdir}
|
||||||
|
cp rhel/systemd/* $RPM_BUILD_ROOT%{_unitdir}/
|
||||||
|
|
||||||
|
[ ! -d $RPM_BUILD_ROOT%{_systemdgeneratordir} ] && mkdir -p $RPM_BUILD_ROOT%{_systemdgeneratordir}
|
||||||
|
python3 tools/render-cloudcfg --variant rhel systemd/cloud-init-generator.tmpl > $RPM_BUILD_ROOT%{_systemdgeneratordir}/cloud-init-generator
|
||||||
|
chmod 755 $RPM_BUILD_ROOT%{_systemdgeneratordir}/cloud-init-generator
|
||||||
|
|
||||||
|
[ ! -d $RPM_BUILD_ROOT/usr/lib/%{name} ] && mkdir -p $RPM_BUILD_ROOT/usr/lib/%{name}
|
||||||
|
cp -p tools/ds-identify $RPM_BUILD_ROOT%{_libexecdir}/%{name}/ds-identify
|
||||||
|
|
||||||
|
# installing man pages
|
||||||
|
mkdir -p ${RPM_BUILD_ROOT}%{_mandir}/man1/
|
||||||
|
for man in cloud-id.1 cloud-init.1 cloud-init-per.1; do
|
||||||
|
install -c -m 0644 doc/man/${man} ${RPM_BUILD_ROOT}%{_mandir}/man1/${man}
|
||||||
|
chmod -x ${RPM_BUILD_ROOT}%{_mandir}/man1/*
|
||||||
|
done
|
||||||
|
|
||||||
|
%clean
|
||||||
|
rm -rf $RPM_BUILD_ROOT
|
||||||
|
|
||||||
|
|
||||||
|
%post
|
||||||
|
if [ $1 -eq 1 ] ; then
|
||||||
|
# Initial installation
|
||||||
|
# Enabled by default per "runs once then goes away" exception
|
||||||
|
/bin/systemctl enable cloud-config.service >/dev/null 2>&1 || :
|
||||||
|
/bin/systemctl enable cloud-final.service >/dev/null 2>&1 || :
|
||||||
|
/bin/systemctl enable cloud-init.service >/dev/null 2>&1 || :
|
||||||
|
/bin/systemctl enable cloud-init-local.service >/dev/null 2>&1 || :
|
||||||
|
/bin/systemctl enable cloud-init.target >/dev/null 2>&1 || :
|
||||||
|
elif [ $1 -eq 2 ]; then
|
||||||
|
# Upgrade. If the upgrade is from a version older than 0.7.9-8,
|
||||||
|
# there will be stale systemd config
|
||||||
|
/bin/systemctl is-enabled cloud-config.service >/dev/null 2>&1 &&
|
||||||
|
/bin/systemctl reenable cloud-config.service >/dev/null 2>&1 || :
|
||||||
|
|
||||||
|
/bin/systemctl is-enabled cloud-final.service >/dev/null 2>&1 &&
|
||||||
|
/bin/systemctl reenable cloud-final.service >/dev/null 2>&1 || :
|
||||||
|
|
||||||
|
/bin/systemctl is-enabled cloud-init.service >/dev/null 2>&1 &&
|
||||||
|
/bin/systemctl reenable cloud-init.service >/dev/null 2>&1 || :
|
||||||
|
|
||||||
|
/bin/systemctl is-enabled cloud-init-local.service >/dev/null 2>&1 &&
|
||||||
|
/bin/systemctl reenable cloud-init-local.service >/dev/null 2>&1 || :
|
||||||
|
|
||||||
|
/bin/systemctl is-enabled cloud-init.target >/dev/null 2>&1 &&
|
||||||
|
/bin/systemctl reenable cloud-init.target >/dev/null 2>&1 || :
|
||||||
|
fi
|
||||||
|
|
||||||
|
%preun
|
||||||
|
if [ $1 -eq 0 ] ; then
|
||||||
|
# Package removal, not upgrade
|
||||||
|
/bin/systemctl --no-reload disable cloud-config.service >/dev/null 2>&1 || :
|
||||||
|
/bin/systemctl --no-reload disable cloud-final.service >/dev/null 2>&1 || :
|
||||||
|
/bin/systemctl --no-reload disable cloud-init.service >/dev/null 2>&1 || :
|
||||||
|
/bin/systemctl --no-reload disable cloud-init-local.service >/dev/null 2>&1 || :
|
||||||
|
/bin/systemctl --no-reload disable cloud-init.target >/dev/null 2>&1 || :
|
||||||
|
# One-shot services -> no need to stop
|
||||||
|
fi
|
||||||
|
|
||||||
|
%postun
|
||||||
|
%systemd_postun cloud-config.service cloud-config.target cloud-final.service cloud-init.service cloud-init.target cloud-init-local.service
|
||||||
|
|
||||||
|
|
||||||
|
%files
|
||||||
|
%license LICENSE
|
||||||
|
%doc ChangeLog rhel/README.rhel
|
||||||
|
%config(noreplace) %{_sysconfdir}/cloud/cloud.cfg
|
||||||
|
%dir %{_sysconfdir}/cloud/cloud.cfg.d
|
||||||
|
%config(noreplace) %{_sysconfdir}/cloud/cloud.cfg.d/*.cfg
|
||||||
|
%doc %{_sysconfdir}/cloud/cloud.cfg.d/README
|
||||||
|
%dir %{_sysconfdir}/cloud/templates
|
||||||
|
%config(noreplace) %{_sysconfdir}/cloud/templates/*
|
||||||
|
%{_unitdir}/cloud-config.service
|
||||||
|
%{_unitdir}/cloud-config.target
|
||||||
|
%{_unitdir}/cloud-final.service
|
||||||
|
%{_unitdir}/cloud-init-local.service
|
||||||
|
%{_unitdir}/cloud-init.service
|
||||||
|
%{_unitdir}/cloud-init.target
|
||||||
|
%{_tmpfilesdir}/%{name}.conf
|
||||||
|
%{python3_sitelib}/*
|
||||||
|
%{_libexecdir}/%{name}
|
||||||
|
%{_bindir}/cloud-init*
|
||||||
|
%doc %{_datadir}/doc/%{name}
|
||||||
|
%{_mandir}/man1/*
|
||||||
|
%dir %verify(not mode) /run/cloud-init
|
||||||
|
%dir /var/lib/cloud
|
||||||
|
/etc/NetworkManager/dispatcher.d/cloud-init-azure-hook
|
||||||
|
%{_udevrulesdir}/66-azure-ephemeral.rules
|
||||||
|
%{_sysconfdir}/bash_completion.d/cloud-init
|
||||||
|
%{_bindir}/cloud-id
|
||||||
|
%{_libexecdir}/%{name}/ds-identify
|
||||||
|
%{_systemdgeneratordir}/cloud-init-generator
|
||||||
|
|
||||||
|
|
||||||
|
%dir %{_sysconfdir}/rsyslog.d
|
||||||
|
%config(noreplace) %{_sysconfdir}/rsyslog.d/21-cloudinit.conf
|
||||||
|
|
||||||
|
%changelog
|
||||||
|
* Mon Aug 16 2021 Miroslav Rezanina <mrezanin@redhat.com> - 21.1-7
|
||||||
|
- ci-Stop-copying-ssh-system-keys-and-check-folder-permis.patch [bz#1979099]
|
||||||
|
- ci-Report-full-specific-version-with-cloud-init-version.patch [bz#1971002]
|
||||||
|
- Resolves: bz#1979099
|
||||||
|
([cloud-init]Customize ssh AuthorizedKeysFile causes login failure[RHEL-9.0])
|
||||||
|
- Resolves: bz#1971002
|
||||||
|
(cloud-init should report full specific full version with "cloud-init --version" [rhel-9])
|
||||||
|
|
||||||
|
* Mon Aug 09 2021 Mohan Boddu <mboddu@redhat.com> - 21.1-6
|
||||||
|
- Rebuilt for IMA sigs, glibc 2.34, aarch64 flags
|
||||||
|
Related: rhbz#1991688
|
||||||
|
|
||||||
|
* Fri Aug 06 2021 Miroslav Rezanina <mrezanin@redhat.com> - 21.1-5
|
||||||
|
- ci-Add-dhcp-client-as-a-dependency.patch [bz#1964900]
|
||||||
|
- Resolves: bz#1964900
|
||||||
|
([Azure][RHEL-9] cloud-init must require dhcp-client on Azure)
|
||||||
|
|
||||||
|
* Thu Jul 15 2021 Miroslav Rezanina <mrezanin@redhat.com> - 21.1-4
|
||||||
|
- ci-write-passwords-only-to-serial-console-lock-down-clo.patch [bz#1945892]
|
||||||
|
- ci-ssh-util-allow-cloudinit-to-merge-all-ssh-keys-into-.patch [bz#1979099]
|
||||||
|
- Resolves: bz#1945892
|
||||||
|
(CVE-2021-3429 cloud-init: randomly generated passwords logged in clear-text to world-readable file [rhel-9.0])
|
||||||
|
- Resolves: bz#1979099
|
||||||
|
([cloud-init]Customize ssh AuthorizedKeysFile causes login failure[RHEL-9.0])
|
||||||
|
|
||||||
|
* Fri Jul 02 2021 Miroslav Rezanina <mrezanin@redhat.com> - 21.1-3
|
||||||
|
- ci-Fix-requiring-device-number-on-EC2-derivatives-836.patch [bz#1943511]
|
||||||
|
- Resolves: bz#1943511
|
||||||
|
([Aliyun][RHEL9.0][cloud-init] cloud-init service failed to start with Alibaba instance)
|
||||||
|
|
||||||
|
* Mon Jun 21 2021 Miroslav Rezanina <mrezanin@redhat.com> - 21.1-2
|
||||||
|
- ci-rhel-cloud.cfg-remove-ssh_genkeytypes-in-settings.py.patch [bz#1970909]
|
||||||
|
- ci-Use-_systemdgeneratordir-macro-for-cloud-init-genera.patch [bz#1971480]
|
||||||
|
- Resolves: bz#1970909
|
||||||
|
([cloud-init] From RHEL 82+ cloud-init no longer displays sshd keys fingerprints from instance launched from a backup image[rhel-9])
|
||||||
|
- Resolves: bz#1971480
|
||||||
|
(Use systemdgenerators macro in spec file)
|
||||||
|
|
||||||
|
* Thu Jun 10 2021 Miroslav Rezanina <mrezanin@redhat.com> - 21.1-1
|
||||||
|
- Rebase to 21.1 [bz#1958209]
|
||||||
|
- Resolves: bz#1958209
|
||||||
|
([RHEL-9.0] Rebase cloud-init to 21.1)
|
||||||
|
|
||||||
|
* Wed Apr 21 2021 Miroslav Rezanina <mrezanin@redhat.com> - 20.4-5
|
||||||
|
- Removing python-mock dependency
|
||||||
|
- Resolves: bz#1922323
|
||||||
|
|
||||||
|
* Thu Apr 15 2021 Mohan Boddu <mboddu@redhat.com> - 20.4-4
|
||||||
|
- Rebuilt for RHEL 9 BETA on Apr 15th 2021. Related: rhbz#1947937
|
||||||
|
|
||||||
|
* Wed Apr 07 2021 Miroslav Rezanina <mrezanin@redhat.com> - 20.4-3.el9
|
||||||
|
- ci-Removing-python-nose-and-python-tox-as-dependency.patch [bz#1916777 bz#1918892]
|
||||||
|
- Resolves: bz#1916777
|
||||||
|
(cloud-init requires python-nose)
|
||||||
|
- Resolves: bz#1918892
|
||||||
|
(cloud-init requires tox)
|
||||||
|
|
||||||
|
* Tue Jan 26 2021 Fedora Release Engineering <releng@fedoraproject.org> - 20.4-2
|
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild
|
||||||
|
|
||||||
|
* Thu Dec 03 2020 Eduardo Otubo <otubo@redhat.com> - 20.4-2
|
||||||
|
- Updated to 20.4 [bz#1902250]
|
||||||
|
|
||||||
|
* Mon Sep 07 2020 Eduardo Otubo <otubo@redhat.com> - 19.4-7
|
||||||
|
- Fix execution fail with backtrace
|
||||||
|
|
||||||
|
* Mon Sep 07 2020 Eduardo Otubo <otubo@redhat.com> - 19.4-6
|
||||||
|
- Adding missing patches to spec file
|
||||||
|
|
||||||
|
* Mon Jul 27 2020 Fedora Release Engineering <releng@fedoraproject.org> - 19.4-5
|
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild
|
||||||
|
|
||||||
|
* Mon May 25 2020 Miro Hrončok <mhroncok@redhat.com> - 19.4-4
|
||||||
|
- Rebuilt for Python 3.9
|
||||||
|
|
||||||
|
* Tue Apr 14 2020 Eduardo Otubo <otubo@redhat.com> - 19.4-3
|
||||||
|
- Fix BZ#1798729 - CVE-2020-8632 cloud-init: Too short random password length
|
||||||
|
in cc_set_password in config/cc_set_passwords.py
|
||||||
|
- Fix BZ#1798732 - CVE-2020-8631 cloud-init: Use of random.choice when
|
||||||
|
generating random password
|
||||||
|
|
||||||
|
* Sun Feb 23 2020 Dusty Mabe <dusty@dustymabe.com> - 19.4-2
|
||||||
|
- Fix sed substitutions for unittest2 and assertItemsEqual
|
||||||
|
- Fix failing unittests by including `BuildRequires: passwd`
|
||||||
|
- The unittests started failing because of upstream commit
|
||||||
|
7c07af2 where cloud-init can now support using `usermod` to
|
||||||
|
lock an account if `passwd` isn't installed. Since `passwd`
|
||||||
|
wasn't installed in our mock buildroot it was choosing to
|
||||||
|
use `usermod` and the unittests were failing. See:
|
||||||
|
https://github.com/canonical/cloud-init/commit/7c07af2
|
||||||
|
- Add missing files to package
|
||||||
|
- /usr/bin/cloud-id
|
||||||
|
- /usr/share/bash-completion/completions/cloud-init
|
||||||
|
|
||||||
|
* Fri Feb 14 2020 Eduardo Otubo <otubo@redhat.com> - 19.4-1
|
||||||
|
- Updated to 19.4
|
||||||
|
- Rebasing the Fedora specific patches but removing patches that don't apply anymore
|
||||||
|
|
||||||
|
* Tue Jan 28 2020 Fedora Release Engineering <releng@fedoraproject.org> - 17.1-15
|
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild
|
||||||
|
|
||||||
|
* Fri Nov 08 2019 Miro Hrončok <mhroncok@redhat.com> - 17.1-14
|
||||||
|
- Drop unneeded build dependency on python3-unittest2
|
||||||
|
|
||||||
|
* Thu Oct 03 2019 Miro Hrončok <mhroncok@redhat.com> - 17.1-13
|
||||||
|
- Rebuilt for Python 3.8.0rc1 (#1748018)
|
||||||
|
|
||||||
|
* Sun Aug 18 2019 Miro Hrončok <mhroncok@redhat.com> - 17.1-12
|
||||||
|
- Rebuilt for Python 3.8
|
||||||
|
|
||||||
|
* Wed Jul 24 2019 Fedora Release Engineering <releng@fedoraproject.org> - 17.1-11
|
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild
|
||||||
|
|
||||||
|
* Tue Apr 23 2019 Björn Esser <besser82@fedoraproject.org> - 17.1-10
|
||||||
|
- Add patch to replace platform.dist() [RH:1695953]
|
||||||
|
- Add (Build)Requires: python3-distro
|
||||||
|
|
||||||
|
* Tue Apr 23 2019 Björn Esser <besser82@fedoraproject.org> - 17.1-9
|
||||||
|
- Fix %%systemd_postun macro [RH:1695953]
|
||||||
|
- Add patch to fix failing test for EPOCHREALTIME bash env [RH:1695953]
|
||||||
|
|
||||||
|
* Thu Jan 31 2019 Fedora Release Engineering <releng@fedoraproject.org> - 17.1-8
|
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild
|
||||||
|
|
||||||
|
* Thu Jul 12 2018 Fedora Release Engineering <releng@fedoraproject.org> - 17.1-7
|
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild
|
||||||
|
|
||||||
|
* Mon Jun 18 2018 Miro Hrončok <mhroncok@redhat.com> - 17.1-6
|
||||||
|
- Rebuilt for Python 3.7
|
||||||
|
|
||||||
|
* Sat Apr 21 2018 Lars Kellogg-Stedman <lars@redhat.com> - 17.1-5
|
||||||
|
- Enable dhcp on EC2 interfaces with only local ipv4 addresses [RH:1569321]
|
||||||
|
(cherry pick upstream commit eb292c1)
|
||||||
|
|
||||||
|
* Mon Mar 26 2018 Patrick Uiterwijk <puiterwijk@redhat.com> - 17.1-4
|
||||||
|
- Make sure the patch does not add infinitely many entries
|
||||||
|
|
||||||
|
* Mon Mar 26 2018 Patrick Uiterwijk <puiterwijk@redhat.com> - 17.1-3
|
||||||
|
- Add patch to retain old values of /etc/sysconfig/network
|
||||||
|
|
||||||
|
* Wed Feb 07 2018 Fedora Release Engineering <releng@fedoraproject.org> - 17.1-2
|
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild
|
||||||
|
|
||||||
|
* Wed Oct 4 2017 Garrett Holmstrom <gholms@fedoraproject.org> - 17.1-1
|
||||||
|
- Updated to 17.1
|
||||||
|
|
||||||
|
* Tue Sep 26 2017 Ryan McCabe <rmccabe@redhat.com> 0.7.9-10
|
||||||
|
- AliCloud: Add support for the Alibaba Cloud datasource (rhbz#1482547)
|
||||||
|
|
||||||
|
* Thu Jun 22 2017 Lars Kellogg-Stedman <lars@redhat.com> 0.7.9-9
|
||||||
|
- RHEL/CentOS: Fix default routes for IPv4/IPv6 configuration. (rhbz#1438082)
|
||||||
|
- azure: ensure that networkmanager hook script runs (rhbz#1440831 rhbz#1460206)
|
||||||
|
- Fix ipv6 subnet detection (rhbz#1438082)
|
||||||
|
|
||||||
|
* Tue May 23 2017 Lars Kellogg-Stedman <lars@redhat.com> 0.7.9-8
|
||||||
|
- Update patches
|
||||||
|
|
||||||
|
* Mon May 22 2017 Lars Kellogg-Stedman <lars@redhat.com> 0.7.9-7
|
||||||
|
- Add missing sysconfig unit test data (rhbz#1438082)
|
||||||
|
- Fix dual stack IPv4/IPv6 configuration for RHEL (rhbz#1438082)
|
||||||
|
- sysconfig: Raise ValueError when multiple default gateways are present. (rhbz#1438082)
|
||||||
|
- Bounce network interface for Azure when using the built-in path. (rhbz#1434109)
|
||||||
|
- Do not write NM_CONTROLLED=no in generated interface config files (rhbz#1385172)
|
||||||
|
|
||||||
|
* Wed May 10 2017 Lars Kellogg-Stedman <lars@redhat.com> 0.7.9-6
|
||||||
|
- add power-state-change module to cloud_final_modules (rhbz#1252477)
|
||||||
|
- remove 'tee' command from logging configuration (rhbz#1424612)
|
||||||
|
- limit permissions on def_log_file (rhbz#1424612)
|
||||||
|
- Bounce network interface for Azure when using the built-in path. (rhbz#1434109)
|
||||||
|
- OpenStack: add 'dvs' to the list of physical link types. (rhbz#1442783)
|
||||||
|
|
||||||
|
* Wed May 10 2017 Lars Kellogg-Stedman <lars@redhat.com> 0.7.9-5
|
||||||
|
- systemd: replace generator with unit conditionals (rhbz#1440831)
|
||||||
|
|
||||||
|
* Thu Apr 13 2017 Charalampos Stratakis <cstratak@redhat.com> 0.7.9-4
|
||||||
|
- Import to RHEL 7
|
||||||
|
Resolves: rhbz#1427280
|
||||||
|
|
||||||
|
* Tue Mar 07 2017 Lars Kellogg-Stedman <lars@redhat.com> 0.7.9-3
|
||||||
|
- fixes for network config generation
|
||||||
|
- avoid dependency cycle at boot (rhbz#1420946)
|
||||||
|
|
||||||
|
* Tue Jan 17 2017 Lars Kellogg-Stedman <lars@redhat.com> 0.7.9-2
|
||||||
|
- use timeout from datasource config in openstack get_data (rhbz#1408589)
|
||||||
|
|
||||||
|
* Thu Dec 01 2016 Lars Kellogg-Stedman <lars@redhat.com> - 0.7.9-1
|
||||||
|
- Rebased on upstream 0.7.9.
|
||||||
|
- Remove dependency on run-parts
|
||||||
|
|
||||||
|
* Wed Jan 06 2016 Lars Kellogg-Stedman <lars@redhat.com> - 0.7.6-8
|
||||||
|
- make rh_subscription plugin do nothing in the absence of a valid
|
||||||
|
configuration [RH:1295953]
|
||||||
|
- move rh_subscription module to cloud_config stage
|
||||||
|
|
||||||
|
* Wed Jan 06 2016 Lars Kellogg-Stedman <lars@redhat.com> - 0.7.6-7
|
||||||
|
- correct permissions on /etc/ssh/sshd_config [RH:1296191]
|
||||||
|
|
||||||
|
* Thu Sep 03 2015 Lars Kellogg-Stedman <lars@redhat.com> - 0.7.6-6
|
||||||
|
- rebuild for ppc64le
|
||||||
|
|
||||||
|
* Tue Jul 07 2015 Lars Kellogg-Stedman <lars@redhat.com> - 0.7.6-5
|
||||||
|
- bump revision for new build
|
||||||
|
|
||||||
|
* Tue Jul 07 2015 Lars Kellogg-Stedman <lars@redhat.com> - 0.7.6-4
|
||||||
|
- ensure rh_subscription plugin is enabled by default
|
||||||
|
|
||||||
|
* Wed Apr 29 2015 Lars Kellogg-Stedman <lars@redhat.com> - 0.7.6-3
|
||||||
|
- added dependency on python-jinja2 [RH:1215913]
|
||||||
|
- added rhn_subscription plugin [RH:1227393]
|
||||||
|
- require pyserial to support smartos data source [RH:1226187]
|
||||||
|
|
||||||
|
* Fri Jan 16 2015 Lars Kellogg-Stedman <lars@redhat.com> - 0.7.6-2
|
||||||
|
- Rebased RHEL version to Fedora rawhide
|
||||||
|
- Backported fix for https://bugs.launchpad.net/cloud-init/+bug/1246485
|
||||||
|
- Backported fix for https://bugs.launchpad.net/cloud-init/+bug/1411829
|
||||||
|
|
||||||
|
* Fri Nov 14 2014 Colin Walters <walters@redhat.com> - 0.7.6-1
|
||||||
|
- New upstream version [RH:974327]
|
||||||
|
- Drop python-cheetah dependency (same as above bug)
|
Loading…
Reference in New Issue
Block a user