krew: Cannot install krew on Windows

Installing krew 0.3.4 on my Windows machine fails consistently with the following error message:

failed to install some plugins: [krew]: install failed: failed while moving files to the installation directory: could not rename/copy directory "C:\\Users\\$me\\AppData\\Local\\Temp\\krew-temp-move638654202" to "C:\\Users\\$me\\.krew\\store\\krew\\v0.3.4": rename C:\Users\$me\AppData\Local\Temp\krew-temp-move638654202 C:\Users\$me\.krew\store\krew\v0.3.4: Access is denied.

I suspect that this issue may be caused by the anti-virus software installed on the corporate laptop, which I cannot disable.

I saw that you already created a fallback for renaming the directory in #375 to fix another edge case. Is there any reason why this fallback cannot be enabled unconditionally? I’m pretty sure that would resolve my issue.

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 1
  • Comments: 28 (7 by maintainers)

Most upvoted comments

Sorry to be blunt @chaoscreater, but please finally read the first few comments in this thread in their entirety: The issue you’re commenting on originally caused the installation to fail even if you could already create symbolic links (thanks to elevation / developer mode). That no longer happens - if you can create symbolic links, the installation now works.

If you think that the fact that symlinks are used in the first place is a bug, please open a new GitHub issue, because this is not the correct thread for that.

Meanwhile to not be blocked by this stuff, I made some script for this, providing this script via our company portal and is executed as a local-admin, it will bluntly copy krew into the any available user in C:\Users\$User\.krew

Re-use by your own liking…

#SCRIPT_USER_HOMEDIR="C:\Windows\System32\Config\systemprofile\"
$scriptUserHomedir = $env:USERPROFILE
$krewVersion = "0.4.3"
$krewTargetBinary = "krew-v${krewVersion}.exe"

Function Test-CommandExists
{
  Param ($command)
 
  $oldPreference = $ErrorActionPreference
  $ErrorActionPreference = ‘stop’

  try {if(Get-Command $command){RETURN $true}}
 
  Catch {Write-Host “$command does not exist”; RETURN $false}

  Finally {$ErrorActionPreference=$oldPreference}
}

# Get current paths
$currentSystemEnvPaths = (Get-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment' -Name PATH).path


# Die if git is not installed.
if(!(Test-CommandExists git)) {
  Write-Error "Git does not exist, let's die" -ErrorAction Stop

} else {
  $gitPath = Get-Command git
  Write-Host "Found git: $gitPath"
}


# Store current location
$startLocation = $PWD.Path

# Note: How is the krew.exe binary made available to C:\Krew ?

# If krew-v{krewVersion}.exe does not exist, pull it.

if (-not(Test-Path -Path "${scriptUserHomedir}\${krewTargetBinary}" -PathType Leaf)) {
  try {
    Invoke-WebRequest -Uri "https://github.com/kubernetes-sigs/krew/releases/download/v${krewVersion}/krew.exe" -OutFile "${scriptUserHomedir}\${krewTargetBinary}"
    Write-Host "Pulled krew-v${krewVersion}.exe from github.com, deleting old krew binary"
    Remove-Item "${scriptUserHomedir}\krew*.exe" -Exclude $krewTargetBinary
   }
   catch {
     throw $_.Exception.Message
   }
   

# If the file already exists, show the message and do nothing.
} 
else {
  Write-Host "${krewTargetBinary} already exists, not pulling."
}


# Install Krew & Plugins
Write-Host "Install krew + plugins"
set-location $scriptUserHomedir
Start-Process -FilePath $(".\" + $krewTargetBinary) -ArgumentList "install krew" -Wait -WindowStyle Hidden
Start-Process -FilePath $(".\" + $krewTargetBinary) -ArgumentList "install oidc-login" -Wait -WindowStyle Hidden
Start-Process -FilePath $(".\" + $krewTargetBinary) -ArgumentList "install auth-proxy" -Wait -WindowStyle Hidden

# Krew is installed in the homedirectory of the System user executing this script
$Source = "${scriptUserHomedir}\.krew"

# Krew is then copied to all users
$Destination = 'C:\users\*\.krew'

# Copy krew to all available users on the system, except for the user executing this script
$userfolders=Get-ChildItem c:\users
$fullpath= "c:\users\"+$env:username
ForEach ($userfolder in $userfolders) {

  if($userfolder.fullname -ne $fullpath) {
    Write-Host "Copy krew to $userfolder"
    Copy-Item -Path $Source -Destination "$($userfolder.fullname)" -Recurse -Force
  } else {
    Write-Host "Don't copy to self ($env:Username)"
  }
}


# Add krew to System Environment Variables permanently if it is not set
if(!($currentSystemEnvPaths.Contains("krew"))) {
  Write-Host "Adding krew to System Environment Path"

  $newSystemPath = "$currentSystemEnvPaths;%USERPROFILE%\.krew\bin"
  Set-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment' -Name PATH -Value $newSystemPath
  
} else {
  Write-Host "Krew already in System Environment Path:\n$currentSystemEnvPaths"
}


refreshenv
set-location $startLocation

Yeah, so to add a little technical colour, some AV implementations hook in post-write, opening and scanning the file after it is written to disk. No implication of TOCTOU race, since they could also have a JIT check in place. But an IO pattern of:

  • creat
  • write
  • close
  • rename (either the file or a containing directory)

will race with the AV scanners

  • open
  • read
  • close calls on Windows OS’s.

Note that the AV scanner is multi threaded, making many of these calls overlapped: trying to thread the needle between them with high frequency attempts is impossible and just increases CPU utilisation.

To fix that, either: don’t perform that IO pattern, or use a retry-with-backoff strategy on the rename. A 10 step Fibonacci sequence retry (in ms, so 1,1,2,3,5,8,13,21,34,55, sum(delay)=143(eep!)) has eliminated reports of this bug for us in Rustup, which drops several hundred MB of HTML on disk in a few seconds - more than enough to cause a backlog for virus scanners that use this particular strategy. Most users get great performance, a few with terrible AV implementations get poor performance. (I say terrible because these files don’t need to be scanned immediately - waiting for some indication they are going to be read would be a better strategy, and safe installation idioms like this represent are extremely common on other platforms than Windows - which is why so many non-Windows heritage programs run into this problem.

Running into similar issue. Suspect same.

For the work around I grabbed the files from: https://github.com/kubernetes-sigs/krew/releases/download/v0.4.0/krew.tar.gz

  • Extracted both the License and krew-windows_amd64.exe.
  • Renamed krew-windows_amd64.exe to krew.exe.
  • Placed both into USERHOME.krew\store\krew\v0.4.0\

I then ran: krew install krew

And it worked.

C:\bin>kubectl krew krew is the kubectl plugin manager.

Looks like I would need to do this for each plugin I would want.