Search code examples
linuxshellcloudrust-cargo

How can I run shell commands for non-root user during cloud-init configuration?


During installation of a cloud VM with cloud-init e.g. when installing Rust toolchain

#cloud-config
package_upgrade: true
packages:
- apt-transport-https
- build-essential
- cmake
runcmd:
- export RUSTUP_HOME=/opt/rust
- export CARGO_HOME=/opt/rust
- curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | bash -s -- -y --no-modify-path --default-toolchain stable --profile default

I also want to execute the toolchain configuration rustup default stable in user space so that it is ready to use when user first signs in.


Solution

  • One key element is to determine the (target/adminsitration) user, that is currently installed on the VM with export USER=$(awk -v uid=1000 -F":" '{ if($3==uid){print $1} }' /etc/passwd), so that environment variable $USER holds the username during the cloud-init configuration process. Then to use sudo -H -u $USER to run a shell in target user's context. Also import is to enhance the user's environment to include the installed toolchain - permanently with extending .profile or alike as well as temporarily while executing this shell operation.

    #cloud-config
    package_upgrade: true
    packages:
    - apt-transport-https
    - build-essential
    - cmake
    runcmd:
    - export USER=$(awk -v uid=1000 -F":" '{ if($3==uid){print $1} }' /etc/passwd)
    - export RUSTUP_HOME=/opt/rust
    - export CARGO_HOME=/opt/rust
    - curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | bash -s -- -y --no-modify-path --default-toolchain stable --profile default
    - echo '\n\n# added by cloud init\nsource /opt/rust/env' >> /home/$USER/.profile
    - sudo -H -u $USER bash -c 'source /opt/rust/env && rustup default stable'
    

    check out complete post with background information