3

I have a golang-based application and associated systemd files in a project. I'm working on a bash script (install.sh) (or a Makefile if that is a better option) that helps to automate the following (basically in this order), but am running into permissions problems:

Goals:

  • Automate building the application binary as a non-root user

  • Copy the systemd file to the correct path (requires elevated permissions)

  • Stop/start the service to load the updated application (requires elevated permissions).

Ideal steps in the bash script:

  • As a non-sudo/non-elevated user, remove the existing binary and rebuild it go build -o binary_name .. This step should be run as my user (compiling code as sudo isn't a great idea.)
  • Elevate permissions
  • Remove the existing /etc/systemd/system/binary_name.service file.
  • Copy the binary_name.service file to /etc/systemd/system/binary_name.service in case it was updated.
  • Stop and restart the binary_name service.

Problems I'm running into: - If I execute sudo install.sh, we run into the "don't compile as sudo/root" issue. Also, the go package isn't found due to different environment settings. - If I executed install.sh without sudo, permission problems crop up when the script attempts to remove/copy the service files.

Following is an abbreviated version of the current script:

#!/bin/bash

case "$1" in
  (das_application) 
    cd /usr/local/apps/das_application/

    # rebuild das_application binary
    echo "Removing old das_application binary"
    rm das_application
    echo "Building updated das_application binary"
    go build -o das_application .
    echo "Done building das_application binary"

    echo "Stopping das_application service"
    sudo systemctl stop das_application

    echo "Copying das_application.service to /etc/systemd/system"
    rm /etc/systemd/system/das_application.service
    cp ./conf/das_application.service /etc/systemd/system/das_application.service

    systemctl daemon-reload

    echo "Starting das_application service"
    systemctl start das_application.service

    exit 1
    ;;
  (*)
    echo "Use as ./install.sh das_application"
    exit 2
    ;;
esac

2 Answers 2

3
+50

Nice question. One of the possible solutions would be checking if script is being run with sudo, exiting if it's not and temporarily dropping privileges to run commands that should be run as a regular user. Something like that:

#!/usr/bin/env sh

if [ -z "$SUDO_USER" ]
then
    printf "Not running with sudo. Exiting\n"
    exit 1
fi

touch SUDO-FILE

# drop privileges temporarily
su "$SUDO_USER" -c 'touch REGULAR-FILE'

After running that you can see 2 files - SUDO-FILE owned by root and its primary group and REGULAR-FILE file owned by the regular user and its primary group:

$ ls -Alhtr SUDO-FILE REGULAR-FILE
-rw-r--r-- 1 root root  0 Dec  5 21:06 SUDO-FILE
-rw-r--r-- 1 ja   users 0 Dec  5 21:06 REGULAR-FILE

Tested on Slackware Linux and FreeBSD. You can also use su -l that will source your regular user's shell login script such as ~/.profile.

I'm not sure what drawbacks and possible gotchas this solution has though so make sure you ran a couple of tests before using it in the production.

0

I would split your script into two:

  • One to build, which doesn't require to be run as root. (your current install.sh that would be renamed build.sh)

  • One to install, which requires to be run as root. (the real deploy.sh).

And, why not a 3rd script that would be called install.sh and would do:

  1. call build.sh regulary.
  2. call sudo deploy.sh
1
  • It's not a good idea to create a 3rd script that would request sudo password in the middle of its execution - it's usually not expected by users, if password is not entered with the time specified it will timeout and the script will fail. Dec 10, 2019 at 19:48

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .