diff --git a/ct/openbao.sh b/ct/openbao.sh new file mode 100644 index 0000000000..9e4c34666e --- /dev/null +++ b/ct/openbao.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +source <(curl -fsSL "${BASE_URL-https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main}"/misc/build.func) +# Copyright (c) 2021-2025 community-scripts ORG +# Author: gpt-5-codex +# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE +# Source: https://github.com/openbao/openbao + +APP="OpenBao" +var_tags="${var_tags:-secrets;vault}" +var_cpu="${var_cpu:-2}" +var_ram="${var_ram:-2048}" +var_disk="${var_disk:-10}" +var_os="${var_os:-debian}" +var_version="${var_version:-13}" +var_unprivileged="${var_unprivileged:-1}" + +header_info "$APP" +variables +color +catch_errors + +function update_script() { + header_info + check_container_storage + check_container_resources + + if [[ ! -f /usr/local/bin/openbao ]] && [[ ! -f /usr/bin/bao ]]; then + msg_error "No ${APP} Installation Found!" + exit + fi + + msg_error "Currently we don't provide an update function for this ${APP}." + exit +} + +start +build_container +description + +msg_ok "Completed Successfully!\n" +echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" +echo -e "${INFO}${YW} Access it using the following URL:${CL}" +echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:8200${CL}" diff --git a/frontend/public/json/openbao.json b/frontend/public/json/openbao.json new file mode 100644 index 0000000000..a4d3ce40db --- /dev/null +++ b/frontend/public/json/openbao.json @@ -0,0 +1,48 @@ +{ + "name": "OpenBao", + "slug": "openbao", + "categories": [ + 6 + ], + "date_created": "2025-10-27", + "type": "ct", + "updateable": true, + "privileged": false, + "interface_port": 8200, + "documentation": "https://openbao.org/docs", + "website": "https://openbao.org/", + "logo": "https://avatars.githubusercontent.com/u/149122427?s=200&v=4", + "config_path": "/etc/openbao/config.hcl", + "description": "OpenBao is an open-source secret management platform that stores, protects, and controls access to sensitive credentials, tokens, and encryption keys with fine-grained policy controls.", + "install_methods": [ + { + "type": "default", + "script": "ct/openbao.sh", + "resources": { + "cpu": 2, + "ram": 2048, + "hdd": 10, + "os": "debian", + "version": "13" + } + } + ], + "default_credentials": { + "username": null, + "password": null + }, + "notes": [ + { + "text": "Initialization details, including the unseal key and root token, are written to `~/openbao.creds`. Secure this file immediately after installation.", + "type": "warning" + }, + { + "text": "OpenBao listens on port `8200` without TLS by default. Enable TLS before exposing the service outside trusted networks.", + "type": "warning" + }, + { + "text": "The file storage backend is configured at `/var/lib/openbao/data`. Back up this directory regularly to retain secrets.", + "type": "info" + } + ] +} diff --git a/install/openbao-install.sh b/install/openbao-install.sh new file mode 100644 index 0000000000..e0221f7311 --- /dev/null +++ b/install/openbao-install.sh @@ -0,0 +1,199 @@ +#!/usr/bin/env bash + +# Copyright (c) 2021-2025 community-scripts ORG +# Author: gpt-5-codex +# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE +# Source: https://github.com/openbao/openbao + +source /dev/stdin <<<"$FUNCTIONS_FILE_PATH" +color +verb_ip6 +catch_errors + +if [[ -z "${OPENBAO_PARENT_INITIALIZED:-}" ]]; then + setting_up_container + network_check + update_os +fi + +msg_info "Installing Dependencies" +$STD apt-get install -y \ + curl \ + sudo \ + mc \ + libcap2-bin \ + openssl +msg_ok "Installed Dependencies" + +msg_info "Creating OpenBao user and directories" +if ! id -u openbao >/dev/null 2>&1; then + useradd --system --home /var/lib/openbao --shell /usr/sbin/nologin openbao +fi +install -d -m 0750 -o openbao -g openbao /var/lib/openbao/data +install -d -m 0750 -o openbao -g openbao /etc/openbao +install -d -m 0750 -o openbao -g openbao /var/log/openbao +msg_ok "Prepared OpenBao user and directories" + +msg_info "Downloading and installing OpenBao" + +# Get latest version from HTML (avoids API rate limit) +RELEASE=$(curl -fsSL https://github.com/openbao/openbao/releases/latest 2>&1 | grep -oP 'openbao/openbao/releases/tag/v\K[0-9.]+' | head -1) + +if [[ -z "$RELEASE" ]]; then + # Fallback: use a known stable version + RELEASE="2.4.3" + msg_info "Could not determine latest version, using v${RELEASE}" +fi + +msg_info "Installing OpenBao v${RELEASE}" + +# Download .deb package directly (no API needed) +DEB_URL="https://github.com/openbao/openbao/releases/download/v${RELEASE}/bao_${RELEASE}_linux_amd64.deb" +TMP_DEB="/tmp/openbao.deb" + +if ! curl -fsSL "$DEB_URL" -o "$TMP_DEB"; then + msg_error "Failed to download from ${DEB_URL}" + exit 1 +fi + +# Install the package +if ! $STD apt install -y "$TMP_DEB"; then + if ! $STD dpkg -i "$TMP_DEB"; then + msg_error "Failed to install OpenBao package" + rm -f "$TMP_DEB" + exit 1 + fi +fi + +rm -f "$TMP_DEB" + +# Create symlink for consistency +if [[ -f /usr/bin/bao ]]; then + ln -sf /usr/bin/bao /usr/local/bin/openbao + msg_ok "Installed OpenBao ${RELEASE}" +else + msg_error "OpenBao binary not found after installation" + exit 1 +fi + +echo "${RELEASE}" >/opt/openbao_version.txt + +msg_info "Configuring OpenBao" +cat >/etc/openbao/config.hcl <<'EOF_CONF' +storage "file" { + path = "/var/lib/openbao/data" +} + +listener "tcp" { + address = "0.0.0.0:8200" + tls_disable = 1 +} + +cluster_addr = "http://127.0.0.1:8201" +api_addr = "http://0.0.0.0:8200" +ui = true + +log_level = "info" +EOF_CONF +chown openbao:openbao /etc/openbao/config.hcl +chmod 640 /etc/openbao/config.hcl +msg_ok "Configured OpenBao" + +create_service() { + local service_name="$1" + local service_content="$2" + printf '%s' "$service_content" >/etc/systemd/system/"${service_name}".service +} + +msg_info "Creating systemd service" + +create_service "openbao" "[Unit] +Description=OpenBao Secrets Management Server +After=network-online.target +Wants=network-online.target +Documentation=https://openbao.org/docs + +[Service] +User=openbao +Group=openbao +ExecStart=/usr/local/bin/openbao server -config=/etc/openbao/config.hcl +ExecReload=/bin/kill --signal HUP \$MAINPID +CapabilityBoundingSet=CAP_IPC_LOCK +AmbientCapabilities=CAP_IPC_LOCK +LimitMEMLOCK=infinity +Restart=on-failure +RestartSec=5s +StartLimitInterval=60 +StartLimitBurst=3 +LogsDirectory=openbao +StandardOutput=journal +StandardError=inherit + +[Install] +WantedBy=multi-user.target +" + +msg_ok "Systemd service created" + +msg_info "Enabling service" +systemctl daemon-reload +if ! systemctl enable -q --now openbao.service; then + msg_error "Failed to enable service. Checking logs..." + echo "=== Status for openbao ===" + systemctl status openbao --no-pager || true + echo "=== Journal for openbao ===" + journalctl -u openbao -n 50 --no-pager || true + exit 1 +fi +msg_ok "Service enabled" + +msg_info "Initializing OpenBao" + +# Wait for OpenBao to be ready +for i in {1..30}; do + if curl -fsS http://127.0.0.1:8200/v1/sys/health >/dev/null 2>&1; then + break + fi + sleep 2 +done + +# Verify OpenBao is actually listening +if ! ss -tlnp | grep -q ':8200'; then + msg_error "OpenBao is running but not listening on port 8200" + ss -tlnp | grep openbao || true + journalctl -u openbao -n 50 --no-pager || true + exit 1 +fi + +export VAULT_ADDR="http://127.0.0.1:8200" + +if ! openbao operator init -status >/dev/null 2>&1; then + INIT_OUTPUT=$(openbao operator init -key-shares=1 -key-threshold=1) + UNSEAL_KEY=$(echo "$INIT_OUTPUT" | awk '/Unseal Key 1/ {print $4}') + ROOT_TOKEN=$(echo "$INIT_OUTPUT" | awk '/Initial Root Token/ {print $4}') + + openbao operator unseal "$UNSEAL_KEY" + + msg_info "Storing administrator credentials" + { + echo "OpenBao Administrator" + echo "Root Token: ${ROOT_TOKEN}" + echo "Unseal Key: ${UNSEAL_KEY}" + echo "" + echo "Full initialization output:" + echo "$INIT_OUTPUT" + } >~/openbao.creds + chmod 600 ~/openbao.creds + msg_ok "Administrator credentials stored in ~/openbao.creds" +else + msg_ok "OpenBao already initialized" +fi + +motd_ssh +customize + +msg_info "Cleaning up" +$STD apt-get -y autoremove +$STD apt-get -y autoclean +$STD apt-get -y clean +msg_ok "Cleaned" diff --git a/misc/build.func b/misc/build.func index b776fdb4bf..be2d6429c9 100644 --- a/misc/build.func +++ b/misc/build.func @@ -129,22 +129,21 @@ variables() { # - Initialize error traps after loading # ------------------------------------------------------------------------------ -source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/api.func) +source <(curl -fsSL "${BASE_URL:-https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main}/misc/api.func") if command -v curl >/dev/null 2>&1; then - source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/core.func) - source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/error_handler.func) + source <(curl -fsSL "${BASE_URL:-https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main}/misc/core.func") + source <(curl -fsSL "${BASE_URL:-https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main}/misc/error_handler.func") load_functions catch_errors #echo "(build.func) Loaded core.func via curl" elif command -v wget >/dev/null 2>&1; then - source <(wget -qO- https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/core.func) - source <(wget -qO- https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/error_handler.func) + source <(wget -qO- "${BASE_URL:-https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main}/misc/core.func") + source <(wget -qO- "${BASE_URL:-https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main}/misc/error_handler.func") load_functions catch_errors #echo "(build.func) Loaded core.func via wget" fi - # ------------------------------------------------------------------------------ # maxkeys_check() # @@ -1267,7 +1266,7 @@ _build_vars_diff() { # Build a temporary .vars file from current advanced settings _build_current_app_vars_tmp() { - tmpf="$(mktemp /tmp/${NSAPP:-app}.vars.new.XXXXXX)" + tmpf="$(mktemp /tmp/"${NSAPP:-app}".vars.new.XXXXXX)" # NET/GW _net="${NET:-}" @@ -1964,7 +1963,7 @@ configure_ssh_settings() { # - Otherwise: shows update/setting menu # ------------------------------------------------------------------------------ start() { - source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/tools.func) + source <(curl -fsSL "${BASE_URL:-https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main}/misc/tools.func") if command -v pveversion >/dev/null 2>&1; then install_script || return 0 return 0 @@ -2069,11 +2068,11 @@ build_container() { fi TEMP_DIR=$(mktemp -d) - pushd "$TEMP_DIR" >/dev/null - if [ "$var_os" == "alpine" ]; then - export FUNCTIONS_FILE_PATH="$(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/alpine-install.func)" + pushd "$TEMP_DIR" >/dev/null || exit +if [ "$var_os" == "alpine" ]; then + export FUNCTIONS_FILE_PATH="$(curl -fsSL "${BASE_URL:-https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main}/misc/alpine-install.func")" else - export FUNCTIONS_FILE_PATH="$(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/install.func)" + export FUNCTIONS_FILE_PATH="$(curl -fsSL "${BASE_URL:-https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main}/misc/install.func")" fi export DIAGNOSTICS="$DIAGNOSTICS" export RANDOM_UUID="$RANDOM_UUID" @@ -2514,7 +2513,7 @@ EOF' install_ssh_keys_into_ct # Run application installer - if ! lxc-attach -n "$CTID" -- bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/install/${var_install}.sh)"; then + if ! lxc-attach -n "$CTID" -- bash -c "$(curl -fsSL "${BASE_URL:-https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main}/install/${var_install}.sh")"; then exit $? fi } @@ -3109,7 +3108,7 @@ create_lxc_container() { #echo "[DEBUG] Selected TEMPLATE='$TEMPLATE' SOURCE='$TEMPLATE_SOURCE'" #msg_debug "Selected TEMPLATE='$TEMPLATE' SOURCE='$TEMPLATE_SOURCE'" - TEMPLATE_PATH="$(pvesm path $TEMPLATE_STORAGE:vztmpl/$TEMPLATE 2>/dev/null || true)" + TEMPLATE_PATH="$(pvesm path "$TEMPLATE_STORAGE":vztmpl/"$TEMPLATE" 2>/dev/null || true)" if [[ -z "$TEMPLATE_PATH" ]]; then TEMPLATE_BASE=$(awk -v s="$TEMPLATE_STORAGE" '$1==s {f=1} f && /path/ {print $2; exit}' /etc/pve/storage.cfg) [[ -n "$TEMPLATE_BASE" ]] && TEMPLATE_PATH="$TEMPLATE_BASE/template/cache/$TEMPLATE" @@ -3174,7 +3173,7 @@ create_lxc_container() { TEMPLATE_SOURCE="online" fi - TEMPLATE_PATH="$(pvesm path $TEMPLATE_STORAGE:vztmpl/$TEMPLATE 2>/dev/null || true)" + TEMPLATE_PATH="$(pvesm path "$TEMPLATE_STORAGE":vztmpl/"$TEMPLATE" 2>/dev/null || true)" if [[ -z "$TEMPLATE_PATH" ]]; then TEMPLATE_BASE=$(awk -v s="$TEMPLATE_STORAGE" '$1==s {f=1} f && /path/ {print $2; exit}' /etc/pve/storage.cfg) [[ -n "$TEMPLATE_BASE" ]] && TEMPLATE_PATH="$TEMPLATE_BASE/template/cache/$TEMPLATE" diff --git a/misc/install.func b/misc/install.func index f741b921d4..b8e6f26178 100644 --- a/misc/install.func +++ b/misc/install.func @@ -9,8 +9,8 @@ if ! command -v curl >/dev/null 2>&1; then apt-get update >/dev/null 2>&1 apt-get install -y curl >/dev/null 2>&1 fi -source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/core.func) -source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/error_handler.func) +source <(curl -fsSL "${BASE_URL:-https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main}/misc/core.func") +source <(curl -fsSL "${BASE_URL:-https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main}/misc/error_handler.func") load_functions catch_errors @@ -54,7 +54,7 @@ setting_up_container() { break fi echo 1>&2 -en "${CROSS}${RD} No Network! " - sleep $RETRY_EVERY + sleep "$RETRY_EVERY" done if [ "$(hostname -I)" = "" ]; then echo 1>&2 -e "\n${CROSS}${RD} No Network After $RETRY_NUM Tries${CL}" @@ -147,7 +147,7 @@ EOF $STD apt-get -o Dpkg::Options::="--force-confold" -y dist-upgrade rm -rf /usr/lib/python3.*/EXTERNALLY-MANAGED msg_ok "Updated Container OS" - source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/tools.func) + source <(curl -fsSL "${BASE_URL:-https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main}/misc/tools.func") } # This function modifies the message of the day (motd) and SSH settings @@ -195,7 +195,7 @@ EOF systemctl restart $(basename $(dirname $GETTY_OVERRIDE) | sed 's/\.d//') msg_ok "Customized Container" fi - echo "bash -c \"\$(curl -fsSL https://github.com/community-scripts/ProxmoxVED/raw/main/ct/${app}.sh)\"" >/usr/bin/update + echo "bash -c \"\$(curl -fsSL ${BASE_URL:-https://github.com/community-scripts/ProxmoxVED/raw/main}/ct/${app}.sh)\"" >/usr/bin/update chmod +x /usr/bin/update if [[ -n "${SSH_AUTHORIZED_KEY}" ]]; then mkdir -p /root/.ssh