PowerShellGetv2 icon indicating copy to clipboard operation
PowerShellGetv2 copied to clipboard

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

Open rybal06 opened this issue 6 years ago • 8 comments

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
  1. 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

  2. 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

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

rybal06 avatar Mar 28 '19 16:03 rybal06

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

SydneyhSmith avatar Mar 28 '19 18:03 SydneyhSmith

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

RobCannon avatar Apr 27 '20 20:04 RobCannon

@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?

alerickson avatar Apr 27 '20 23:04 alerickson

@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 avatar Apr 29 '20 14:04 RobCannon

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 avatar Apr 29 '20 14:04 RobCannon

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.

RobCannon avatar May 01 '20 14:05 RobCannon

@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)

jocobwknight avatar Jun 10 '21 00:06 jocobwknight

/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!

RobCannon avatar Jun 11 '21 20:06 RobCannon