Skip to content

Commit 917223f

Browse files
author
Madda
committed
CFY-3532-run-services-as-non-root
1 parent 3666e4e commit 917223f

File tree

8 files changed

+113
-7
lines changed

8 files changed

+113
-7
lines changed

components/mgmtworker/config/cloudify-mgmtworker.service

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ TimeoutStartSec=0
66
Restart=on-failure
77
EnvironmentFile=-/etc/sysconfig/cloudify-mgmtworker
88
WorkingDirectory=/opt/mgmtworker/work
9+
User={{ ctx.instance.runtime_properties.mgmtworker_user }}
10+
Group={{ ctx.instance.runtime_properties.mgmtworker_group }}
911
ExecStart=/opt/mgmtworker/env/bin/celery worker \
1012
-Ofair \
1113
--include=cloudify_system_workflows.snapshot,cloudify_system_workflows.deployment_environment,cloudify_agent.operations,cloudify_agent.installer.operations,riemann_controller.tasks,cloudify.plugins.workflows \

components/mgmtworker/scripts/create.sh

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,22 @@ export PLUGINS_COMMON_SOURCE_URL=$(ctx node properties plugins_common_module_sou
1010
export SCRIPT_PLUGIN_SOURCE_URL=$(ctx node properties script_plugin_module_source_url)
1111
export REST_SERVICE_SOURCE_URL=$(ctx node properties rest_service_module_source_url)
1212
export AGENT_SOURCE_URL=$(ctx node properties agent_module_source_url)
13+
export SSH_KEY_FILE=$(ctx node properties ssh_key_filename)
14+
export AGENT_USER=$(ctx node properties agents_user)
1315

1416
# This will only be used if the management worker is not installed via an RPM
1517
export CELERY_VERSION="3.1.17"
1618

19+
export MGMTWORKER_USER='cloudifymgmtworker'
20+
export MGMTWORKER_GROUP='cloudifymgmtworker'
21+
export MGMTWORKER_HOME="/opt/mgmtworker"
22+
1723
# these must all be exported as part of the start operation. they will not persist, so we should use the new agent
1824
# don't forget to change all localhosts to the relevant ips
19-
export MGMTWORKER_HOME="/opt/mgmtworker"
2025
export MGMTWORKER_VIRTUALENV_DIR="${MGMTWORKER_HOME}/env"
2126
export CELERY_WORK_DIR="${MGMTWORKER_HOME}/work"
2227
export CELERY_LOG_DIR="/var/log/cloudify/mgmtworker"
28+
export MGMTWORKER_RIEMANN_POLICY_DIR="/opt/riemann"
2329

2430
# Set broker port for rabbit
2531
export BROKER_PORT_SSL="5671"
@@ -28,6 +34,8 @@ export RABBITMQ_SSL_ENABLED="$(ctx -j node properties rabbitmq_ssl_enabled)"
2834
export RABBITMQ_CERT_PUBLIC="$(ctx node properties rabbitmq_cert_public)"
2935

3036
ctx instance runtime_properties rabbitmq_endpoint_ip "$(get_rabbitmq_endpoint_ip)"
37+
ctx instance runtime_properties mgmtworker_user ${MGMTWORKER_USER}
38+
ctx instance runtime_properties mgmtworker_group ${MGMTWORKER_GROUP}
3139

3240
# Fix possible injections in json of rabbit credentials
3341
# See json.org for string spec
@@ -51,6 +59,12 @@ create_dir ${MGMTWORKER_HOME}/config
5159
create_dir ${CELERY_LOG_DIR}
5260
create_dir ${CELERY_WORK_DIR}
5361

62+
create_service_user ${MGMTWORKER_USER} ${MGMTWORKER_HOME} /bin/bash
63+
64+
# This directory is populated when deployments are created- counterintuitively it does need to live here rather than the riemann component
65+
create_dir ${MGMTWORKER_RIEMANN_POLICY_DIR}
66+
set_directory_tree_ownership ${MGMTWORKER_USER} ${MGMTWORKER_GROUP} ${MGMTWORKER_RIEMANN_POLICY_DIR}
67+
5468
# this create the MGMTWORKER_VIRTUALENV_DIR and installs the relevant modules into it.
5569
yum_install ${MANAGEMENT_WORKER_RPM_SOURCE_URL}
5670

@@ -98,4 +112,27 @@ for python_path in ${MGMTWORKER_VIRTUALENV_DIR}/lib/python*; do
98112
# The config contains credentials, do not let the world read it
99113
chmod 440 "${BROKER_CONF_PATH}"
100114
done
115+
116+
# Copy or move key files to appropriate locations
117+
if sudo test -f /root/.ssh/agent_key.pem; then
118+
sudo mv /root/.ssh/agent_key.pem /opt/mgmtworker
119+
else
120+
# If the key file wasn't where we expected then we're probably running a simple-manager-blueprint
121+
# If this fails, the management worker wouldn't be able to ssh into any compute nodes, so failing is acceptable
122+
# Using this ugly approach because tilde expansion isn't working here. This should be fixed when we standardise
123+
# key locations.
124+
sudo cp ${SSH_KEY_FILE/\~/\/home\/${AGENT_USER}} /opt/mgmtworker/agent_key.pem
125+
fi
126+
127+
# Set ownership
128+
set_directory_tree_ownership ${MGMTWORKER_USER} ${MGMTWORKER_GROUP} ${MGMTWORKER_HOME}
129+
set_directory_tree_ownership ${MGMTWORKER_USER} ${MGMTWORKER_GROUP} ${MGMTWORKER_VIRTUALENV_DIR}
130+
set_directory_tree_ownership ${MGMTWORKER_USER} ${MGMTWORKER_GROUP} ${CELERY_WORK_DIR}
131+
set_directory_tree_ownership ${MGMTWORKER_USER} ${MGMTWORKER_GROUP} ${CELERY_LOG_DIR}
132+
133+
# Management worker has to create services
134+
# TODO: It would be better if we made a specific script and allowed sudo only for that script to allow the services to be created.
135+
# This requires modifications to the agent as well, and may require modification to the agent installer.
136+
allow_sudo_for_user ${MGMTWORKER_USER}
137+
101138
configure_systemd_service "mgmtworker"

components/restservice/config/cloudify-restservice.service

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,16 @@ Description=Cloudify REST Service
55
PIDFile=/var/run/gunicorn.pid
66
TimeoutStartSec=0
77
Restart=on-failure
8+
User={{ ctx.source.instance.runtime_properties.rest_service_user }}
9+
Group={{ ctx.source.instance.runtime_properties.rest_service_group }}
810
EnvironmentFile=-/etc/sysconfig/cloudify-restservice
911
ExecStart=/bin/sh -c '/opt/manager/env/bin/gunicorn \
10-
--pid /var/run/gunicorn.pid \
12+
--pid {{ ctx.source.instance.runtime_properties.rest_service_pid_dir }}/gunicorn.pid \
1113
-w $(($(nproc)*2+1)) \
1214
-b 0.0.0.0:${REST_SERVICE_PORT} \
1315
--timeout 300 manager_rest.server:app \
1416
--log-file /var/log/cloudify/rest/gunicorn.log \
1517
--access-logfile /var/log/cloudify/rest/gunicorn-access.log'
1618

1719
[Install]
18-
WantedBy=multi-user.target
20+
WantedBy=multi-user.target

components/restservice/scripts/create.sh

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,23 @@ export PLUGINS_COMMON_SOURCE_URL=$(ctx node properties plugins_common_module_sou
1919
export SCRIPT_PLUGIN_SOURCE_URL=$(ctx node properties script_plugin_module_source_url)
2020
export AGENT_SOURCE_URL=$(ctx node properties agent_module_source_url)
2121

22+
# TODO: change to /opt/cloudify-rest-service
23+
export REST_SERVICE_HOME="/opt/manager"
24+
export REST_SERVICE_USER='cloudifyrest'
25+
export REST_SERVICE_GROUP='cloudifyrest'
26+
export REST_SERVICE_PID_DIR='/var/run/rest'
27+
2228
# injected as an input to the script
2329
ctx instance runtime_properties es_endpoint_ip ${ES_ENDPOINT_IP}
2430

2531
ctx instance runtime_properties rabbitmq_endpoint_ip "$(get_rabbitmq_endpoint_ip)"
32+
ctx instance runtime_properties rest_service_user ${REST_SERVICE_USER}
33+
ctx instance runtime_properties rest_service_group ${REST_SERVICE_GROUP}
34+
ctx instance runtime_properties rest_service_pid_dir ${REST_SERVICE_PID_DIR}
2635

2736
export RABBITMQ_SSL_ENABLED="$(ctx -j node properties rabbitmq_ssl_enabled)"
2837
export RABBITMQ_CERT_PUBLIC="$(ctx node properties rabbitmq_cert_public)"
2938

30-
# TODO: change to /opt/cloudify-rest-service
31-
export REST_SERVICE_HOME="/opt/manager"
3239
export MANAGER_RESOURCES_HOME="/opt/manager/resources"
3340
export RESTSERVICE_VIRTUALENV="${REST_SERVICE_HOME}/env"
3441
# guni.conf currently contains localhost for all endpoints. We need to change that.
@@ -45,6 +52,9 @@ copy_notice "restservice"
4552
create_dir ${REST_SERVICE_HOME}
4653
create_dir ${REST_SERVICE_LOG_PATH}
4754
create_dir ${MANAGER_RESOURCES_HOME}
55+
create_dir ${REST_SERVICE_PID_DIR}
56+
57+
create_service_user ${REST_SERVICE_USER} ${REST_SERVICE_HOME}
4858

4959
# Add certificate and select port, as applicable
5060
if [[ "${RABBITMQ_SSL_ENABLED}" == 'true' ]]; then
@@ -96,3 +106,13 @@ deploy_logrotate_config "restservice"
96106
ctx logger info "Deploying REST Service Configuration file..."
97107
# rest service ports are set as runtime properties in nginx/scripts/create.sh
98108
deploy_blueprint_resource "${CONFIG_REL_PATH}/cloudify-rest.conf" "${REST_SERVICE_HOME}/cloudify-rest.conf"
109+
110+
# Set ownership
111+
set_directory_tree_ownership ${REST_SERVICE_USER} ${REST_SERVICE_GROUP} ${REST_SERVICE_HOME}
112+
set_directory_tree_ownership root ${REST_SERVICE_USER} ${REST_SERVICE_HOME}/env
113+
set_directory_tree_ownership ${REST_SERVICE_USER} ${REST_SERVICE_GROUP} ${REST_SERVICE_LOG_PATH}
114+
set_directory_tree_ownership ${REST_SERVICE_USER} ${REST_SERVICE_GROUP} ${REST_SERVICE_PID_DIR}
115+
116+
# Improve permissions
117+
# Nothing in the env should be writable by the rest service- that's the site code
118+
sudo find ${REST_SERVICE_HOME}/env -exec chmod g-w {} \;

components/riemann/config/cloudify-riemann.service

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ Description=Riemann Service
44
[Service]
55
TimeoutStartSec=0
66
Restart=always
7+
User={{ ctx.instance.runtime_properties.riemann_user }}
8+
Group={{ ctx.instance.runtime_properties.riemann_group }}
79
EnvironmentFile=-/etc/sysconfig/cloudify-riemann
810
ExecStart=/usr/bin/riemann -a ${RIEMANN_CONFIG_PATH}/main.clj
911

1012
[Install]
11-
WantedBy=multi-user.target
13+
WantedBy=multi-user.target

components/riemann/scripts/create.sh

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ export EXTRA_CLASSPATH="${LANGOHR_HOME}/langohr.jar"
1919
export RABBITMQ_USERNAME="$(ctx node properties rabbitmq_username)"
2020
export RABBITMQ_PASSWORD="$(ctx node properties rabbitmq_password)"
2121

22+
export RIEMANN_USER='riemann'
23+
export RIEMANN_GROUP='riemann'
24+
export RIEMANN_HOME='/var/lib/riemann'
25+
2226
# Confirm username and password have been supplied for broker before continuing
2327
# Components other than logstash and riemann have this handled in code already
2428
# Note that these are not directly used in this script, but are used by the deployed resources, hence the check here.
@@ -28,6 +32,8 @@ if [[ -z "${RABBITMQ_USERNAME}" ]] ||
2832
fi
2933

3034
ctx instance runtime_properties rabbitmq_endpoint_ip "$(get_rabbitmq_endpoint_ip)"
35+
ctx instance runtime_properties riemann_user ${RIEMANN_USER}
36+
ctx instance runtime_properties riemann_group ${RIEMANN_GROUP}
3137

3238
ctx logger info "Installing Riemann..."
3339
set_selinux_permissive
@@ -38,6 +44,14 @@ create_dir ${LANGOHR_HOME}
3844
create_dir ${RIEMANN_CONFIG_PATH}
3945
create_dir ${RIEMANN_CONFIG_PATH}/conf.d
4046

47+
create_service_user ${RIEMANN_USER} ${RIEMANN_HOME}
48+
create_dir ${RIEMANN_HOME}
49+
50+
# Set ownership
51+
set_directory_tree_ownership ${RIEMANN_USER} ${RIEMANN_GROUP} ${RIEMANN_HOME}
52+
set_directory_tree_ownership ${RIEMANN_USER} ${RIEMANN_GROUP} ${RIEMANN_LOG_PATH}
53+
set_directory_tree_ownership root ${RIEMANN_GROUP} ${RIEMANN_CONFIG_PATH}
54+
4155
langohr=$(download_cloudify_resource ${LANGOHR_SOURCE_URL})
4256
sudo cp ${langohr} ${EXTRA_CLASSPATH}
4357
ctx logger info "Applying Langohr permissions..."

components/utils

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,7 @@ function create_service_user() {
376376
###
377377
user=$1
378378
home=$2
379+
shell=${3:-/sbin/nologin}
379380

380381
ctx logger info "Checking if ${user} exists..."
381382
ret=false
@@ -385,7 +386,7 @@ function create_service_user() {
385386
ctx logger info "User ${user} already exists..."
386387
else
387388
ctx logger info "Creating user ${user} with home ${home}..."
388-
sudo useradd --shell /sbin/nologin --home-dir "${home}" --no-create-home --system "${user}"
389+
sudo useradd --shell ${shell} --home-dir "${home}" --no-create-home --system "${user}"
389390
fi
390391
}
391392

@@ -526,4 +527,24 @@ function get_rabbitmq_endpoint_ip() {
526527
echo "${RABBITMQ_ENDPOINT_IP}"
527528
}
528529

530+
function allow_sudo_for_user() {
531+
###
532+
# Allow a given user passwordless sudo
533+
###
534+
username=${1}
535+
536+
sudo bash -c "echo '${username} ALL=(ALL) NOPASSWD: ALL' > /etc/sudoers.d/${username} && visudo -c -f /etc/sudoers || (rm /etc/sudoers.d/${username} && false)" || sys_error "Failed to allow sudo for ${username}"
537+
}
538+
539+
function set_directory_tree_ownership() {
540+
###
541+
# Set the ownership of a directory tree.
542+
###
543+
user=${1}
544+
group=${2}
545+
directory=${3}
546+
547+
sudo chown -R ${user}.${group} ${directory}
548+
}
549+
529550
CLOUDIFY_SOURCES_PATH="/opt/cloudify/sources"

types/manager-types.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -581,6 +581,14 @@ node_types:
581581
manager.nodes.ManagementWorker:
582582
derived_from: cloudify.nodes.ApplicationModule
583583
properties:
584+
agents_user:
585+
description: User for agents.
586+
type: string
587+
default: { get_input: agents_user }
588+
ssh_key_filename:
589+
description: SSH key file for accessing agents
590+
type: string
591+
default: { get_input: ssh_key_filename }
584592
management_worker_rpm_source_url:
585593
description: Management Worker RPM Source URL
586594
type: string

0 commit comments

Comments
 (0)