PowerShell / PowerShellGetv2

PowerShellGet is the Package Manager for PowerShell
https://www.PowerShellGallery.com
MIT License
432 stars 138 forks source link

Modules do not work for non-root users when umask values are set to be more restrictive than default #457

Open rybal06 opened 5 years ago

rybal06 commented 5 years ago

Steps to reproduce

  1. Edit all default umask entries inside of /etc/bashrc & /etc/profile to 077. Re-source files, reboot host, or log out/log in to refresh user profile.

  2. Verify that umask value has been updated for root user

    [root@rhel7 ~]# umask
    0077
  3. As root, install powershell core by following RHEL directions: https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell-core-on-linux?view=powershell-6

  4. As a non-root user, attempt to install a powershell module to currentuser scope (join-object is used only as an example here)

PS /home/user> Install-Module Join-Object -Scope CurrentUser

NuGet provider is required to continue
This version of PowerShellGet requires minimum version '2.8.5.201' of NuGet provider to publish an item to NuGet-based repositories. The NuGet provider must be available in '' or ''. You 
can also install the NuGet provider by running 'Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force'. Do you want PowerShellGet to install and import the NuGet provider 
now?
[Y] Yes  [N] No  [S] Suspend  [?] Help (default is "Y"): y
PackageManagement\Install-PackageProvider : Unhandled Exception - Message:'The type initializer for 'Microsoft.PackageManagement.Internal.Utility.Extensions.FilesystemExtensions' threw an exception.' Name:'TypeInitializationException' Stack Trace:'   at Microsoft.PackageManagement.Internal.Utility.Extensions.FilesystemExtensions.MakeSafeFileName(String input)
   at Microsoft.PackageManagement.Internal.Utility.Plugin.DynamicType.DefineDynamicType(Type interfaceType)
   at Microsoft.PackageManagement.Internal.Utility.Plugin.DynamicType..ctor(Type interfaceType, OrderedDictionary`2 methods, List`2 delegates, List`1 stubs)
   at Microsoft.PackageManagement.Internal.Utility.Plugin.DynamicType.<>c__DisplayClass9_0.<Create>b__4()
   at Microsoft.PackageManagement.Internal.Utility.Extensions.DictionaryExtensions.GetOrAdd[TKey,TValue](IDictionary`2 dictionary, TKey key, Func`1 valueFunction)
   at Microsoft.PackageManagement.Internal.Utility.Plugin.DynamicType.Create(Type tInterface, OrderedDictionary`2 instanceMethods, List`2 delegateMethods, List`1 stubMethods, List`2 usedInstances)
   at Microsoft.PackageManagement.Internal.Utility.Plugin.DynamicInterface.CreateProxy(Type tInterface, Object[] instances)
   at Microsoft.PackageManagement.Internal.Utility.Plugin.DynamicInterface.DynamicCast(Type tInterface, Object[] instances)
   at Microsoft.PackageManagement.Internal.Utility.Plugin.DynamicInterface.DynamicCast[TInterface](Object[] instances)
   at Microsoft.PowerShell.PackageManagement.Cmdlets.CmdletBase.SelectProviders(String[] names)
   at Microsoft.PowerShell.PackageManagement.Cmdlets.CmdletWithProvider.get_SelectedProviders()
   at Microsoft.PowerShell.PackageManagement.Cmdlets.InstallPackageProvider.get_SelectedProviders()
   at Microsoft.PowerShell.PackageManagement.Cmdlets.CmdletWithProvider.<get_CachedSelectedProviders>b__23_0()
   at Microsoft.PackageManagement.Internal.Utility.Extensions.DictionaryExtensions.GetOrAdd[TKey,TValue](IDictionary`2 dictionary, TKey key, Func`1 valueFunction)
   at Microsoft.PowerShell.PackageManagement.Cmdlets.CmdletWithProvider.GenerateDynamicParameters()
   at Microsoft.PowerShell.PackageManagement.Cmdlets.AsyncCmdlet.<>c__DisplayClass83_0.<AsyncRun>b__0()'
At /opt/microsoft/powershell/6/Modules/PowerShellGet/PSModule.psm1:3270 char:21
+ ...     $null = PackageManagement\Install-PackageProvider -Name $script:N ...
+                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : InvalidOperation: (Microsoft.Power...PackageProvider:InstallPackageProvider) [Install-PackageProvider], Exception
+ FullyQualifiedErrorId : UnhandledException,Microsoft.PowerShell.PackageManagement.Cmdlets.InstallPackageProvider

PackageManagement\Import-PackageProvider : No match was found for the specified search criteria and provider name 'NuGet'. Try 'Get-PackageProvider -ListAvailable' to see if the provider exists on the system.
At /opt/microsoft/powershell/6/Modules/PowerShellGet/PSModule.psm1:3276 char:21
+ ...     $null = PackageManagement\Import-PackageProvider -Name $script:Nu ...
+                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : InvalidData: (NuGet:String) [Import-PackageProvider], Exception
+ FullyQualifiedErrorId : NoMatchFoundForCriteria,Microsoft.PowerShell.PackageManagement.Cmdlets.ImportPackageProvider

PackageManagement\Get-PackageProvider : Unhandled Exception - Message:'The type initializer for 'Microsoft.PackageManagement.Internal.Utility.Extensions.FilesystemExtensions' threw an exception.' Name:'TypeInitializationException' Stack Trace:'   at Microsoft.PackageManagement.Internal.Utility.Extensions.FilesystemExtensions.MakeSafeFileName(String input)
   at Microsoft.PackageManagement.Internal.Utility.Plugin.DynamicType.DefineDynamicType(Type interfaceType)
   at Microsoft.PackageManagement.Internal.Utility.Plugin.DynamicType..ctor(Type interfaceType, OrderedDictionary`2 methods, List`2 delegates, List`1 stubs)
   at Microsoft.PackageManagement.Internal.Utility.Plugin.DynamicType.<>c__DisplayClass9_0.<Create>b__4()
   at Microsoft.PackageManagement.Internal.Utility.Extensions.DictionaryExtensions.GetOrAdd[TKey,TValue](IDictionary`2 dictionary, TKey key, Func`1 valueFunction)
   at Microsoft.PackageManagement.Internal.Utility.Plugin.DynamicType.Create(Type tInterface, OrderedDictionary`2 instanceMethods, List`2 delegateMethods, List`1 stubMethods, List`2 usedInstances)
   at Microsoft.PackageManagement.Internal.Utility.Plugin.DynamicInterface.CreateProxy(Type tInterface, Object[] instances)
   at Microsoft.PackageManagement.Internal.Utility.Plugin.DynamicInterface.DynamicCast(Type tInterface, Object[] instances)
   at Microsoft.PackageManagement.Internal.Utility.Plugin.DynamicInterface.DynamicCast[TInterface](Object[] instances)
   at Microsoft.PowerShell.PackageManagement.Cmdlets.CmdletBase.SelectProviders(String name)
   at Microsoft.PowerShell.PackageManagement.Cmdlets.GetPackageProvider.ProcessProvidersFilteredByName()
   at Microsoft.PowerShell.PackageManagement.Cmdlets.GetPackageProvider.ProcessRecordAsync()
   at Microsoft.PowerShell.PackageManagement.Cmdlets.AsyncCmdlet.<>c__DisplayClass83_0.<AsyncRun>b__0()'
At /opt/microsoft/powershell/6/Modules/PowerShellGet/PSModule.psm1:3280 char:30
+ ... tProvider = PackageManagement\Get-PackageProvider -Name $script:NuGet ...
+                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : InvalidOperation: (Microsoft.Power...PackageProvider:GetPackageProvider) [Get-PackageProvider], Exception
+ FullyQualifiedErrorId : UnhandledException,Microsoft.PowerShell.PackageManagement.Cmdlets.GetPackageProvider

Install-Module : NuGet provider is required to interact with NuGet-based repositories. Please ensure that '2.8.5.201' or newer version of NuGet provider is installed.
At line:1 char:1
+ Install-Module Join-Object -Scope CurrentUser
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : InvalidOperation: (:) [Install-Module], InvalidOperationException
+ FullyQualifiedErrorId : CouldNotInstallNuGetProvider,Install-Module
  1. Additionally, install a powershell module as root in the allusers scope; and note it is not accessible by non-root users:
    
    PS /root> Install-Module join-Object -force   
    PS /root> Get-Module -ListAvailable                                                                                                                                                                                                                                                                                                                                                                                                                                                           Directory: /usr/local/share/powershell/Modules                                                                                                                                                                                                                                                                          

ModuleType Version Name PSEdition ExportedCommands


Script 1.0.1 Join-Object Desk Join-Object

Directory: /opt/microsoft/powershell/6/Modules

ModuleType Version Name PSEdition ExportedCommands


Manifest 1.2.2.0 Microsoft.PowerShell.Archive Desk {Compress-Archive, Expand-Archive} Manifest 6.1.0.0 Microsoft.PowerShell.Host Core {Start-Transcript, Stop-Transcript} Manifest 6.1.0.0 Microsoft.PowerShell.Management Core {Add-Content, Clear-Content, Clear-ItemProperty, Join-Path...} Manifest 6.1.0.0 Microsoft.PowerShell.Security Core {Get-Credential, Get-ExecutionPolicy, Set-ExecutionPolicy, ConvertFrom-SecureString...} Manifest 6.1.0.0 Microsoft.PowerShell.Utility Core {Format-List, Format-Custom, Format-Table, Format-Wide...} Script 1.1.7.2 PackageManagement Desk {Find-Package, Get-Package, Get-PackageProvider, Get-PackageSource...} Script 1.6.7 PowerShellGet Desk {Find-Command, Find-DSCResource, Find-Module, Find-RoleCapability...} Script 0.0 PSDesiredStateConfiguration Desk {GetResourceFromKeyword, GetSyntax, Update-ConfigurationErrorCount, Write-MetaConfigFi... Script 2.0.0 PSReadLine Desk {Get-PSReadLineKeyHandler, Set-PSReadLineKeyHandler, Remove-PSReadLineKeyHandler, Get-... Binary 1.1.2 ThreadJob Desk Start-ThreadJob

PS /home/user> Get-Module -ListAvailable

Directory: /opt/microsoft/powershell/6/Modules

ModuleType Version Name PSEdition ExportedCommands


Manifest 1.2.2.0 Microsoft.PowerShell.Archive Desk {Compress-Archive, Expand-Archive} Manifest 6.1.0.0 Microsoft.PowerShell.Host Core {Start-Transcript, Stop-Transcript} Manifest 6.1.0.0 Microsoft.PowerShell.Management Core {Add-Content, Clear-Content, Clear-ItemProperty, Join-Path...} Manifest 6.1.0.0 Microsoft.PowerShell.Security Core {Get-Credential, Get-ExecutionPolicy, Set-ExecutionPolicy, ConvertFrom-SecureString...} Manifest 6.1.0.0 Microsoft.PowerShell.Utility Core {Format-List, Format-Custom, Format-Table, Format-Wide...} Script 1.1.7.2 PackageManagement Desk {Find-Package, Get-Package, Get-PackageProvider, Get-PackageSource...} Script 1.6.7 PowerShellGet Desk {Find-Command, Find-DSCResource, Find-Module, Find-RoleCapability...} Script 0.0 PSDesiredStateConfiguration Desk {GetPatterns, Get-CompatibleVersionAddtionaPropertiesStr, Get-ComplexResourceQualifier... Script 2.0.0 PSReadLine Desk {Get-PSReadLineKeyHandler, Set-PSReadLineKeyHandler, Remove-PSReadLineKeyHandler, Get-... Binary 1.1.2 ThreadJob Desk Start-ThreadJob


# Expected behavior

The Powershell RPM package and module installations should set explicit permissions, rather than assuming that the umask is set as OS default. 

This would allow non-root users to use powershell modules in higher-security environments-- for example CIS benchmarks require changing default umask values.

# Actual behavior

Module usage is not possible for non-root users when default umask value is changed.

# Environment data

<!-- provide the output of $PSVersionTable -->

```none
PS /root> $PSVersionTable                                                                                                                                                                                                                                                                                                 Name                           Value                                                                                                                         ----                           -----                                                                                                                         PSVersion                      6.1.3
PSEdition                      Core
GitCommitId                    6.1.3
OS                             Linux 3.10.0-957.1.3.el7.x86_64 #1 SMP Thu Nov 15 17:36:42 UTC 2018
Platform                       Unix
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0
SydneyhSmith commented 5 years ago

@rybal06 thanks for reporting this issue, we will investigate this further! CC:\ @alerickson

RobCannon commented 4 years ago

Is there a work-around for this? We are seeing this behavior and it is blocking powershell usage on our hardened centos servers.

alerickson commented 4 years ago

@RobCannon I'll properly address this issue with the GA of PowerShellGet v3, but as a workaround, could you try changing the umask value to 002 before installation?

RobCannon commented 4 years ago

@alerickson I tried this command to install on a fresh image and it does not work: sudo -- sh -c 'umask 002; yum install -y powershell'

I think I could fix this by setting file permissions explicitly on specific directories. Do you know which directories should be changed?

RobCannon commented 4 years ago

Running this seems to fix problems with finding modules. But installing modules still does not work.

sudo chmod 755 -R /usr/local/share/powershell

Get-PackageProvider is still not working. Not sure what file/directory it is trying to use. The permissions of /opt/microsoft/powershell/7 look right to me. It is -rw-r--r-- on .dll and most other files and -rwxr-xr-x for executables. Everything works if I run 'sudo pwsh', but we are trying to get this installed for non-root users.

This is the error I get from Get-PackageProvider:

Get-PackageProvider: Unhandled Exception - Message:'The type initializer for 'Microsoft.PackageManagement.Internal.Utility.Extensions.FilesystemExtensions' threw an exception.' Name:'TypeInitializationException' Stack Trace:'   at Microsoft.PackageManagement.Internal.Utility.Extensions.FilesystemExtensions.MakeSafeFileName(String input)
   at Microsoft.PackageManagement.Internal.Utility.Plugin.DynamicType.DefineDynamicType(Type interfaceType)
   at Microsoft.PackageManagement.Internal.Utility.Plugin.DynamicType..ctor(Type interfaceType, OrderedDictionary`2 methods, List`2 delegates, List`1 stubs)
   at Microsoft.PackageManagement.Internal.Utility.Plugin.DynamicType.<>c__DisplayClass9_0.<Create>b__3()
   at Microsoft.PackageManagement.Internal.Utility.Extensions.DictionaryExtensions.GetOrAdd[TKey,TValue](IDictionary`2 dictionary, TKey key, Func`1 valueFunction)
   at Microsoft.PackageManagement.Internal.Utility.Plugin.DynamicType.Create(Type tInterface, OrderedDictionary`2 instanceMethods, List`2 delegateMethods, List`1 stubMethods, List`2 usedInstances)
   at Microsoft.PackageManagement.Internal.Utility.Plugin.DynamicInterface.CreateProxy(Type tInterface, Object[] instances)
   at Microsoft.PackageManagement.Internal.Utility.Plugin.DynamicInterface.DynamicCast(Type tInterface, Object[] instances)
   at Microsoft.PackageManagement.Internal.Utility.Plugin.DynamicInterface.DynamicCast[TInterface](Object[] instances)
   at Microsoft.PackageManagement.Internal.Utility.Plugin.DynamicInterfaceExtensions.As[TInterface](Object instance)
   at Microsoft.PowerShell.PackageManagement.Cmdlets.CmdletBase.get_PackageManagementHost()
   at Microsoft.PowerShell.PackageManagement.Cmdlets.CmdletBase.SelectProviders(String[] names)
   at Microsoft.PowerShell.PackageManagement.Cmdlets.GetPackageProvider.ProcessRecordAsync()
   at Microsoft.PowerShell.PackageManagement.Cmdlets.AsyncCmdlet.<>c__DisplayClass83_0.<AsyncRun>b__0()'
RobCannon commented 4 years ago

I was able to fix the issues for us. As part of our image creation script, we were installing powershell, but also later running a script to install some modules into the AllUsers scope. The servers from this image will be used in places that are blocked from the internet, so we need to get the module baked into the image.

Anyway, when that script runs, it is running under the hardened umask 077. The /usr/local/share/powershell isn't created until the first modules are installed and the directory is created with the wrong file permissions. Powershell reacts badly and it messes up lots of aspects of modules.

So, the full work around is this (for centos 7):

curl -s https://packages.microsoft.com/config/rhel/7/prod.repo | sudo tee /etc/yum.repos.d/microsoft.repo
sudo -- sh -c 'umask 002; yum install -y powershell'
sudo chmod +x /tmp/powershell_init.ps1
sudo -- sh -c 'umask 002; /tmp/powershell_init.ps1'

Note that the powershell_init.ps1 has a hashbabg (#!/bin/pwsh) so it will automatically be invoked via the pwsh executable. Also note that my earlier attempt to fix things with 'sudo chmod 755 -R /usr/local/share/powershell' is NOT needed with this workaround.

jocobwknight commented 3 years ago

@RobCannon, I never thank random strangers, but thank you so much for posting that! I've been trying to make a RedHat/Windows cross-platform PowerCLI utility and nothing I tried (including chmod 755) could get it to run as a non-root user. I completely uninstalled everything and used your workaround and it worked! (Although /tmp/powershell_init.ps1 didn't exist on my RH system so I did the chmod 755 for good measure)

RobCannon commented 3 years ago

/tmp/powershell_init.ps1 is our script for installing some common modules on the server. If you don't need that, you can omit that step. Glad I was able to help!