Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/actions/deployment_create.rb
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ def clone_existing_web_process(app, revision, process_instances)
state: ProcessModel::STOPPED,
instances: process_instances,
command: command,
user: web_process.user,
memory: web_process.memory,
file_descriptors: web_process.file_descriptors,
disk_quota: web_process.disk_quota,
Expand Down
1 change: 1 addition & 0 deletions app/actions/process_update.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ def update(process, message, strategy_class)
end

process.command = strategy.updated_command if message.requested?(:command)
process.user = message.user if message.requested?(:user)
process.health_check_timeout = message.health_check_timeout if message.requested?(:health_check_timeout)

process.health_check_invocation_timeout = message.health_check_invocation_timeout if message.requested?(:health_check_invocation_timeout)
Expand Down
12 changes: 11 additions & 1 deletion app/messages/process_update_message.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

module VCAP::CloudController
class ProcessUpdateMessage < MetadataBaseMessage
register_allowed_keys %i[command health_check readiness_health_check]
register_allowed_keys %i[command user health_check readiness_health_check]

# rubocop:disable Metrics/CyclomaticComplexity
def initialize(params={})
Expand All @@ -25,6 +25,10 @@ def self.command_requested?
@command_requested ||= proc { |a| a.requested?(:command) }
end

def self.user_requested?
@user_requested ||= proc { |a| a.requested?(:user) }
end

validates_with NoAdditionalKeysValidator

validates :command,
Expand All @@ -33,6 +37,12 @@ def self.command_requested?
allow_nil: true,
if: command_requested?

validates :user,
string: true,
length: { in: 1..255, message: 'must be between 1 and 255 characters' },
allow_nil: true,
if: user_requested?

validates :health_check_type,
inclusion: {
in: [HealthCheckTypes::PORT, HealthCheckTypes::PROCESS, HealthCheckTypes::HTTP],
Expand Down
1 change: 1 addition & 0 deletions app/models.rb
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
require 'models/runtime/constraints/readiness_health_check_policy'
require 'models/runtime/constraints/docker_policy'
require 'models/runtime/constraints/sidecar_memory_less_than_process_memory_policy'
require 'models/runtime/constraints/process_user_policy'
require 'models/runtime/revision_model'
require 'models/runtime/revision_process_command_model'
require 'models/runtime/revision_sidecar_model'
Expand Down
26 changes: 26 additions & 0 deletions app/models/runtime/constraints/process_user_policy.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
class ProcessUserPolicy
ERROR_MSG = 'invalid (requested user %<requested_user>s not allowed, permitted users are: %<allowed_users>s)'.freeze

def initialize(process, allowed_users)
@process = process
@allowed_users = allowed_users
@errors = process.errors
end

def validate
return if @process.user.blank?
return if @allowed_users.map(&:downcase).include?(@process.user.downcase)

@errors.add(:user, sprintf(ERROR_MSG, requested_user: quote_user(@process.user), allowed_users: formatted_users_for_error))
end

private

def formatted_users_for_error
@allowed_users.map { |u| quote_user(u) }.join(', ')
end

def quote_user(user)
"'#{user}'"
end
end
30 changes: 25 additions & 5 deletions app/models/runtime/process_model.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
require_relative 'buildpack'

module VCAP::CloudController
class ProcessModel < Sequel::Model(:processes)
class ProcessModel < Sequel::Model(:processes) # rubocop:disable Metrics/ClassLength
include Serializer

plugin :serialization
Expand All @@ -34,7 +34,8 @@ def after_initialize
NO_APP_PORT_SPECIFIED = -1
DEFAULT_HTTP_PORT = 8080
DEFAULT_PORTS = [DEFAULT_HTTP_PORT].freeze
UNLIMITED_LOG_RATE = -1
DEFAULT_USER = 'vcap'.freeze
UNLIMITED_LOG_RATE = -1

many_to_one :app, class: 'VCAP::CloudController::AppModel', key: :app_guid, primary_key: :guid, without_guid_generation: true
many_to_one :revision, class: 'VCAP::CloudController::RevisionModel', key: :revision_guid, primary_key: :guid, without_guid_generation: true
Expand Down Expand Up @@ -267,7 +268,8 @@ def validation_policies
ReadinessHealthCheckPolicy.new(self, readiness_health_check_invocation_timeout, readiness_health_check_type, readiness_health_check_http_endpoint,
readiness_health_check_interval),
DockerPolicy.new(self),
PortsPolicy.new(self)
PortsPolicy.new(self),
ProcessUserPolicy.new(self, permitted_users)
]
end

Expand Down Expand Up @@ -391,6 +393,12 @@ def started_command
specified_commands[type] || revision.droplet&.process_start_command(type) || ''
end

def run_action_user
return user if user.present?

docker? ? docker_run_action_user : DEFAULT_USER
end

def specified_or_detected_command
command.presence || detected_start_command
end
Expand Down Expand Up @@ -446,15 +454,15 @@ def debug

delegate :cnb?, to: :app

delegate :windows_gmsa_credential_refs, to: :app

def database_uri
service_binding_uris = service_bindings.map do |binding|
binding.credentials['uri'] if binding.credentials.present?
end.compact
DatabaseUriGenerator.new(service_binding_uris).database_uri
end

delegate :windows_gmsa_credential_refs, to: :app

def max_app_disk_in_mb
VCAP::CloudController::Config.config.get(:maximum_app_disk_in_mb)
end
Expand Down Expand Up @@ -564,6 +572,18 @@ def open_ports

private

def permitted_users
Set.new([DEFAULT_USER]) + Config.config.get(:additional_allowed_process_users)
end

def docker_run_action_user
return DEFAULT_USER unless docker?

docker_exec_metadata = Oj.load(execution_metadata)
container_user = docker_exec_metadata['user']
container_user.presence || 'root'
end

def non_unique_process_types
return [] unless app

Expand Down
1 change: 1 addition & 0 deletions app/presenters/v3/process_presenter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ def to_hash
version: process.version,
type: process.type,
command: redact(process.specified_or_detected_command),
user: process.run_action_user,
instances: process.instances,
memory_in_mb: process.memory,
disk_in_mb: process.disk_quota,
Expand Down
1 change: 1 addition & 0 deletions config/cloud_controller.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ maximum_app_disk_in_mb: 2048
max_retained_deployments_per_app: 100
max_retained_builds_per_app: 100
max_retained_revisions_per_app: 100
additional_allowed_process_users: ['ContainerUser']

broker_client_default_async_poll_interval_seconds: 60
broker_client_max_async_poll_duration_minutes: 10080
Expand Down
13 changes: 13 additions & 0 deletions db/migrations/20250610212414_add_user_to_processes.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Sequel.migration do
up do
alter_table :processes do
add_column :user, String, null: true, default: nil, size: 255 unless @db.schema(:processes).map(&:first).include?(:user)
end
end

down do
alter_table :processes do
drop_column :user if @db.schema(:processes).map(&:first).include?(:user)
end
end
end
3 changes: 3 additions & 0 deletions docs/v3/source/includes/api_resources/_processes.erb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"guid": "6a901b7c-9417-4dc1-8189-d3234aa0ab82",
"type": "web",
"command": "rackup",
"user": "vcap",
"instances": 5,
"memory_in_mb": 256,
"disk_in_mb": 1024,
Expand Down Expand Up @@ -80,6 +81,7 @@
"guid": "6a901b7c-9417-4dc1-8189-d3234aa0ab82",
"type": "web",
"command": "[PRIVATE DATA HIDDEN IN LISTS]",
"user": "vcap",
"instances": 5,
"memory_in_mb": 256,
"disk_in_mb": 1024,
Expand Down Expand Up @@ -141,6 +143,7 @@
"guid": "3fccacd9-4b02-4b96-8d02-8e865865e9eb",
"type": "worker",
"command": "[PRIVATE DATA HIDDEN IN LISTS]",
"user": "vcap",
"instances": 1,
"memory_in_mb": 256,
"disk_in_mb": 1024,
Expand Down
1 change: 1 addition & 0 deletions docs/v3/source/includes/resources/processes/_object.md.erb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Name | Type | Description
**version** | _uuid_ | Random identifier that changes every time the process will be recreated in the runtime.
**type** | _string_ | Process type; a unique identifier for processes belonging to an app
**command** | _string_ or _null_ | The command used to start the process; use _null_ to revert to the buildpack-detected or procfile-provided start command
**user** | _string_ or _null_ | The user used to run the process; use _null_ to revert to the docker-detected or default 'vcap' user
**instances** | _integer_ | The number of instances to run
**memory_in_mb** | _integer_ | The memory in MB allocated per instance
**log_rate_limit_in_bytes_per_second** | _integer_ | The log rate in bytes per second allocated per instance
Expand Down
1 change: 1 addition & 0 deletions lib/cloud_controller/config_schemas/base/api_schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class ApiSchema < VCAP::Config
maximum_app_disk_in_mb: Integer,
default_health_check_timeout: Integer,
maximum_health_check_timeout: Integer,
optional(:additional_allowed_process_users) => Array,

instance_file_descriptor_limit: Integer,

Expand Down
1 change: 1 addition & 0 deletions lib/cloud_controller/config_schemas/base/clock_schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ class ClockSchema < VCAP::Config
max_retained_deployments_per_app: Integer,
max_retained_builds_per_app: Integer,
max_retained_revisions_per_app: Integer,
optional(:additional_allowed_process_users) => Array,

diego_sync: { frequency_in_seconds: Integer },

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ class DeploymentUpdaterSchema < VCAP::Config
default_app_disk_in_mb: Integer,
maximum_app_disk_in_mb: Integer,
instance_file_descriptor_limit: Integer,
optional(:additional_allowed_process_users) => Array,

deployment_updater: {
update_frequency_in_seconds: Integer,
Expand Down
1 change: 1 addition & 0 deletions lib/cloud_controller/config_schemas/base/worker_schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ class WorkerSchema < VCAP::Config
maximum_app_disk_in_mb: Integer,
default_app_log_rate_limit_in_bytes_per_second: Integer,
default_app_ssh_access: bool,
optional(:additional_allowed_process_users) => Array,

jobs: {
global: {
Expand Down
7 changes: 2 additions & 5 deletions lib/cloud_controller/diego/buildpack/desired_lrp_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ class DesiredLrpBuilder
include ::Diego::ActionBuilder
class InvalidStack < StandardError; end

attr_reader :start_command
attr_reader :start_command, :action_user

def initialize(config, opts)
@config = config
Expand All @@ -17,6 +17,7 @@ def initialize(config, opts)
@checksum_algorithm = opts[:checksum_algorithm]
@checksum_value = opts[:checksum_value]
@start_command = opts[:start_command]
@action_user = opts[:action_user]
@additional_container_env_vars = opts[:additional_container_env_vars]
end

Expand Down Expand Up @@ -115,10 +116,6 @@ def port_environment_variables
def privileged?
@config.get(:diego, :use_privileged_containers_for_running)
end

def action_user
'vcap'
end
end
end
end
Expand Down
7 changes: 2 additions & 5 deletions lib/cloud_controller/diego/cnb/desired_lrp_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ class DesiredLrpBuilder
include ::Diego::ActionBuilder
class InvalidStack < StandardError; end

attr_reader :start_command
attr_reader :start_command, :action_user

def initialize(config, opts)
@config = config
Expand All @@ -17,6 +17,7 @@ def initialize(config, opts)
@checksum_algorithm = opts[:checksum_algorithm]
@checksum_value = opts[:checksum_value]
@start_command = opts[:start_command]
@action_user = opts[:action_user]
@additional_container_env_vars = opts[:additional_container_env_vars]
end

Expand Down Expand Up @@ -114,10 +115,6 @@ def privileged?
@config.get(:diego, :use_privileged_containers_for_running)
end

def action_user
'vcap'
end

private

def default_container_env
Expand Down
13 changes: 2 additions & 11 deletions lib/cloud_controller/diego/docker/desired_lrp_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@ module VCAP::CloudController
module Diego
module Docker
class DesiredLrpBuilder
attr_reader :start_command
attr_reader :start_command, :action_user

def initialize(config, opts)
@config = config
@docker_image = opts[:docker_image]
@execution_metadata = opts[:execution_metadata]
@ports = opts[:ports]
@start_command = opts[:start_command]
@action_user = opts[:action_user]
@additional_container_env_vars = opts[:additional_container_env_vars]
end

Expand Down Expand Up @@ -68,16 +69,6 @@ def port_environment_variables
def privileged?
false
end

def action_user
execution_metadata = Oj.load(@execution_metadata)
user = execution_metadata['user']
if user.nil? || user.empty?
'root'
else
user
end
end
end
end
end
Expand Down
1 change: 1 addition & 0 deletions lib/cloud_controller/diego/docker/lifecycle_protocol.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ def builder_opts(process)
docker_image: process.actual_droplet.docker_receipt_image,
execution_metadata: process.execution_metadata,
start_command: process.command,
action_user: process.run_action_user,
additional_container_env_vars: container_env_vars_for_process(process)
}
end
Expand Down
1 change: 1 addition & 0 deletions lib/cloud_controller/diego/lifecycle_protocol.rb
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ def builder_opts(process)
checksum_algorithm: checksum_info['type'],
checksum_value: checksum_info['value'],
start_command: process.started_command,
action_user: process.run_action_user,
additional_container_env_vars: container_env_vars_for_process(process)
}
end
Expand Down
Loading