mirror of
https://github.com/apple/container.git
synced 2026-10-12 09:11:25 +00:00
- Closes #2321. - Removes image script and ORAS resource extension point handling for container machine user setup. - Replaces image script resource with hardcoded script. - Adds more flexible user setup options to `container machine`. - Updates container machine documentation to clearly identify convenience-isolation tradeoffs.
85 lines
4.1 KiB
Swift
85 lines
4.1 KiB
Swift
//===----------------------------------------------------------------------===//
|
|
// Copyright © 2026 Apple Inc. and the container project authors.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// https://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// Container machine user setup, embedded as a literal and exec'd directly
|
|
/// inside the guest (as `sh -c "\(MachineUserSetup.script)"`) rather than
|
|
/// shipped as a file. Intended to be image-agnostic by directly manipulating
|
|
/// /etc/group, /etc/passwd, and /etc/shadow rather than relying on
|
|
/// image-specific tools (useradd, adduser, etc.).
|
|
///
|
|
/// Safe to run on every boot: user/shadow creation and home directory
|
|
/// population only happen once (guarded by looking the account up by both
|
|
/// uid and username), while the sudoers entry is cheaply reasserted every
|
|
/// run. If the image already has a *different* account using the requested
|
|
/// uid or username, or anything already exists at the requested home path,
|
|
/// setup fails loudly instead of silently skipping — proceeding could mean
|
|
/// resolving to the wrong account, creating a duplicate/ambiguous passwd
|
|
/// entry, or recursively chowning pre-existing content that isn't ours.
|
|
///
|
|
/// Expects CONTAINER_USER, CONTAINER_UID, CONTAINER_GID, and CONTAINER_HOME
|
|
/// to be set in the environment.
|
|
public enum MachineUserSetup {
|
|
public static let script = #"""
|
|
set -e
|
|
|
|
. /etc/os-release 2>/dev/null || true
|
|
case "${ID:-}" in
|
|
ubuntu|debian)
|
|
CONTAINER_SHELL=$(unset DSHELL; . /etc/adduser.conf 2>/dev/null \
|
|
&& [ -n "${DSHELL:-}" ] \
|
|
&& echo "${DSHELL}") || CONTAINER_SHELL=/bin/bash ;;
|
|
*)
|
|
CONTAINER_SHELL=$(unset SHELL; . /etc/default/useradd 2>/dev/null \
|
|
&& [ -n "${SHELL:-}" ] \
|
|
&& echo "${SHELL}") || CONTAINER_SHELL=/bin/sh ;;
|
|
esac
|
|
|
|
if ! getent group "${CONTAINER_GID}" >/dev/null 2>&1; then
|
|
echo "${CONTAINER_USER}:x:${CONTAINER_GID}:" >> /etc/group
|
|
fi
|
|
|
|
existing_by_uid=$(getent passwd "${CONTAINER_UID}" 2>/dev/null) || true
|
|
existing_by_name=$(getent passwd "${CONTAINER_USER}" 2>/dev/null) || true
|
|
|
|
if [ -n "${existing_by_uid}" ] || [ -n "${existing_by_name}" ]; then
|
|
if [ "${existing_by_uid}" != "${existing_by_name}" ]; then
|
|
echo "container machine: refusing to provision user '${CONTAINER_USER}' (uid ${CONTAINER_UID}): a different account in this image already uses this uid or username" >&2
|
|
exit 1
|
|
fi
|
|
# Otherwise this is our own account from a previous boot: nothing to do.
|
|
else
|
|
if [ -e "${CONTAINER_HOME}" ]; then
|
|
echo "container machine: refusing to use existing path '${CONTAINER_HOME}' as the home directory for user '${CONTAINER_USER}'" >&2
|
|
exit 1
|
|
fi
|
|
|
|
echo "${CONTAINER_USER}:x:${CONTAINER_UID}:${CONTAINER_GID}::${CONTAINER_HOME}:${CONTAINER_SHELL}" >> /etc/passwd
|
|
echo "${CONTAINER_USER}:!:$(($(date +%s) / 86400)):0:99999:7:::" >> /etc/shadow
|
|
|
|
mkdir -p "${CONTAINER_HOME}"
|
|
if [ -d /etc/skel ]; then
|
|
cp -a /etc/skel/. "${CONTAINER_HOME}"
|
|
fi
|
|
chown -R "${CONTAINER_UID}:${CONTAINER_GID}" "${CONTAINER_HOME}"
|
|
fi
|
|
|
|
mkdir -p /etc/sudoers.d
|
|
sudoers_file=$(echo "${CONTAINER_USER}" | tr '.' '_')
|
|
echo "${CONTAINER_USER} ALL=(ALL) NOPASSWD:ALL" > "/etc/sudoers.d/${sudoers_file}"
|
|
chmod 440 "/etc/sudoers.d/${sudoers_file}"
|
|
"""#
|
|
}
|