13

I have a shell provisioner in packer connected to a box with user vagrant

{
  "environment_vars": [
    "HOME_DIR=/home/vagrant"
  ],
  "expect_disconnect": true,
  "scripts": [
    "scripts/foo.sh"
  ],
  "type": "shell"
}

where the content of the script is:

whoami
sudo su
whoami

and the output strangely remains:

==> virtualbox-ovf: Provisioning with shell script: scripts/configureProxies.sh
    virtualbox-ovf: vagrant
    virtualbox-ovf: vagrant

why cant I switch to the root user? How can I execute statements as root? Note, I do not want to quote all statements like sudo "statement |foo" but rather globally switch user like demonstrated with sudo su

Alex Harvey
  • 14,494
  • 5
  • 61
  • 97
Georg Heiler
  • 16,916
  • 36
  • 162
  • 292

4 Answers4

12

You should override the execute_command. Example:

  "provisioners": [
    {
      "execute_command": "echo 'vagrant' | {{.Vars}} sudo -S -E sh -eux '{{.Path}}'",
      "scripts": [
        "scripts/foo.sh"
      ],
      "type": "shell"
    }
  ],
Rickard von Essen
  • 4,110
  • 2
  • 23
  • 27
  • But when using your solution ` virtualbox-ovf: bash: line 1: vagrant: command not found` is the output in case I want to switch back to the vagrant user for some other commands via `su vagrant`. Is there a solution for switching users which is better than my initial answer? – Georg Heiler Jan 31 '18 at 16:11
  • If you are `root` just prefix any command you want to run as another user with `sudo -u `. – Rickard von Essen Feb 01 '18 at 18:20
3

There is another solution with simpler usage of 2 provisioner together.

Packer's shell provisioner can run the bash with sudo privileges. First you need copy your script file from local machine to remote with file provisioner, then run it with shell provisioner.

packer.json

{
    "vars": [...],
    "builders": [
        {
            # ...
            "ssh_username": "<some_user_other_than_root_with_passwordless_sudo>",
        }
    ],
    "provisioners": [
        {
            "type": "file",
            "source": "scripts/foo.sh",
            "destination": "~/shell.tmp.sh"
        },
        {
            "type": "shell",
            "inline": ["sudo bash ~/shell.tmp.sh"]
        }
    ]
}

foo.sh

# ...
whoami
sudo su root
whoami
# ...

output

<some_user_other_than_root_with_passwordless_sudo>
root

After provisioner complete its task, you can delete the file with shell provisioner.

packer.json updated

        {
            "type": "shell",
            "inline": ["sudo bash ~/shell.tmp.sh", "rm ~/shell.tmp.sh"]
        }
ufukty
  • 312
  • 3
  • 10
1

one possible answer seems to be: https://unix.stackexchange.com/questions/70859/why-doesnt-sudo-su-in-a-shell-script-run-the-rest-of-the-script-as-root

sudo su <<HERE
ls /root
whoami
HERE

maybe there is a better answer?

Georg Heiler
  • 16,916
  • 36
  • 162
  • 292
0

Assuming that the shell provisioner you are using is a bash script, you can add my technique to your script.

function if_not_root_rerun_as_root(){
    install_self
    if [[ "$(id -u)" -ne 0 ]]; then
        run_as_root_keeping_exports "$0" "$@"
        exit $?
    fi
}

function run_as_root_keeping_exports(){
    eval sudo $(for x in $_EXPORTS; do printf '%s=%q ' "$x" "${!x}"; done;) "$@"
}

export EXPORTS="PACKER_BUILDER_TYPE PACKER_BUILD_NAME"
if_not_root_rerun_as_root "$@"

There is a pretty good explanation of "$@" here on StackOverflow.

Bruno Bronosky
  • 66,273
  • 12
  • 162
  • 149