Skip to content

Commit

Permalink
Linux permissions winrm credentials (#37)
Browse files Browse the repository at this point in the history
  • Loading branch information
leefine02 authored Apr 22, 2022
1 parent 219b96b commit f2f46b2
Show file tree
Hide file tree
Showing 14 changed files with 79 additions and 30 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
v2.3
- Add new config.json setting DefaultLinuxPermissionsOnStoreCreation, and certificate store type custom parameter linuxFilePermissionsOnStoreCreation
- Add ability to use client machine credentials for WinRM Windows servers rather than always using the Keyfactor service account



v2.2
- Limit the valid characters that can be used for store paths to protect against command injection.

Expand Down
Binary file modified Images/Image12.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Images/custom-field-5.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified Images/setup-3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions PEMStoreSSH/ApplicationSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ class ApplicationSettings
public static string SeparateUploadFilePath { get; set; }
public static bool UseNegotiateAuth { get; set; }
public static bool UseSCP { get; set; }
public static string DefaultLinuxPermissionsOnStoreCreation { get; set; }

private const string DEFAULT_LINUX_PERMISSION_SETTING = "600";

public static void Initialize(string currLocation)
{
Expand All @@ -40,6 +43,7 @@ public static void Initialize(string currLocation)
SeparateUploadFilePath = AddTrailingSlash(jsonContents.SeparateUploadFilePath.Value);
UseNegotiateAuth = jsonContents.UseNegotiateAuth.Value.Equals("Y", System.StringComparison.OrdinalIgnoreCase);
UseSCP = jsonContents.UseSCP == null || !jsonContents.UseSCP.Value.Equals("Y", System.StringComparison.OrdinalIgnoreCase) ? false : true;
DefaultLinuxPermissionsOnStoreCreation = jsonContents.DefaultLinuxPermissionsOnStoreCreation == null ? DEFAULT_LINUX_PERMISSION_SETTING : jsonContents.DefaultLinuxPermissionsOnStoreCreation.Value;
}

private static string AddTrailingSlash(string path)
Expand Down
16 changes: 10 additions & 6 deletions PEMStoreSSH/Management.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,11 @@ public JobResult ProcessJob(ManagementJobConfiguration config)
{
throw new PEMException("Certificate store is set has having a separate private key but no private key path is specified in the store definition.");
}


string linuxFilePermissions = properties.linuxFilePermissionsOnStoreCreation == null || string.IsNullOrEmpty(properties.linuxFilePermissionsOnStoreCreation.Value) ?
ApplicationSettings.DefaultLinuxPermissionsOnStoreCreation :
properties.linuxFilePermissionsOnStoreCreation.Value;

PEMStore pemStore = new PEMStore
(
certStore.ClientMachine,
Expand Down Expand Up @@ -67,9 +71,9 @@ public JobResult ProcessJob(ManagementJobConfiguration config)

if (ApplicationSettings.CreateStoreOnAddIfMissing && !storeExists)
{
pemStore.CreateEmptyStoreFile(certStore.StorePath);
pemStore.CreateEmptyStoreFile(certStore.StorePath, linuxFilePermissions);
if (hasSeparatePrivateKey && privateKeyPath != null)
pemStore.CreateEmptyStoreFile(privateKeyPath);
pemStore.CreateEmptyStoreFile(privateKeyPath, linuxFilePermissions);
}

if (!ApplicationSettings.CreateStoreOnAddIfMissing && !storeExists)
Expand All @@ -95,7 +99,7 @@ public JobResult ProcessJob(ManagementJobConfiguration config)
throw new PEMException($"Certificate store {certStore.StorePath} does not exist.");
}

pemStore.RemoveCertificate(jobCert.Alias);
pemStore.RemoveCertificate(jobCert.Alias, linuxFilePermissions);

break;

Expand All @@ -105,10 +109,10 @@ public JobResult ProcessJob(ManagementJobConfiguration config)
throw new PEMException($"Certificate store {certStore.StorePath} already exists and cannot be created.");
}

pemStore.CreateEmptyStoreFile(certStore.StorePath);
pemStore.CreateEmptyStoreFile(certStore.StorePath, linuxFilePermissions);
if (hasSeparatePrivateKey && privateKeyPath != null)
{
pemStore.CreateEmptyStoreFile(privateKeyPath);
pemStore.CreateEmptyStoreFile(privateKeyPath, linuxFilePermissions);
}

break;
Expand Down
8 changes: 4 additions & 4 deletions PEMStoreSSH/PEMStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ internal X509Certificate2Collection GetCertificates(string storePassword, out bo
}
}

internal void RemoveCertificate(string alias)
internal void RemoveCertificate(string alias, string linuxFilePermissions)
{
try
{
Expand All @@ -159,7 +159,7 @@ internal void RemoveCertificate(string alias)
{
mutex.WaitOne();
SSH.RemoveCertificateFile(PrivateKeyPath);
SSH.CreateEmptyStoreFile(PrivateKeyPath);
SSH.CreateEmptyStoreFile(PrivateKeyPath, linuxFilePermissions);
}
catch (Exception ex)
{
Expand Down Expand Up @@ -196,9 +196,9 @@ internal bool IsValidStore(string path)
return CertificateHandler.IsValidStore(path, ServerType, SSH);
}

internal void CreateEmptyStoreFile(string path)
internal void CreateEmptyStoreFile(string path, string linuxFilePermissions)
{
SSH.CreateEmptyStoreFile(path);
SSH.CreateEmptyStoreFile(path, linuxFilePermissions);
}

internal bool IsStorePathValid(string path)
Expand Down
2 changes: 1 addition & 1 deletion PEMStoreSSH/RemoteHandlers/BaseRemoteHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public BaseRemoteHandler()

public abstract void RemoveCertificateFile(string path);

public abstract void CreateEmptyStoreFile(string path);
public abstract void CreateEmptyStoreFile(string path, string linuxFilePermissions);

}
}
2 changes: 1 addition & 1 deletion PEMStoreSSH/RemoteHandlers/IRemoteHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,6 @@ interface IRemoteHandler

void RemoveCertificateFile(string path);

void CreateEmptyStoreFile(string path);
void CreateEmptyStoreFile(string path, string linuxFilePermissions);
}
}
17 changes: 14 additions & 3 deletions PEMStoreSSH/RemoteHandlers/SSHHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,15 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using System.Text;

namespace Keyfactor.Extensions.Orchestrator.PEMStoreSSH.RemoteHandlers
{
class SSHHandler : BaseRemoteHandler
{
private const string LINUX_PERMISSION_REGEXP = "^[0-7]{3}$";

private ConnectionInfo Connection { get; set; }

internal SSHHandler(string server, string serverLogin, string serverPassword)
Expand Down Expand Up @@ -79,7 +82,7 @@ public override string RunCommand(string commandText, object[] arguments, bool w
_logger.LogDebug($"RunCommand: {displayCommand}");
command.Execute();
_logger.LogDebug($"SSH Results: {displayCommand}::: {command.Result}::: {command.Error}");
return command.Result;
return commandText.StartsWith("ls ", StringComparison.OrdinalIgnoreCase) && string.IsNullOrEmpty(command.Result) && !string.IsNullOrEmpty(command.Error) ? command.Error : command.Result;
}
}
finally
Expand Down Expand Up @@ -247,9 +250,10 @@ public override void RemoveCertificateFile(string path)
RunCommand($"rm {path}", null, ApplicationSettings.UseSudo, null);
}

public override void CreateEmptyStoreFile(string path)
public override void CreateEmptyStoreFile(string path, string linuxFilePermissions)
{
RunCommand($"touch {path}", null, ApplicationSettings.UseSudo, null);
AreLinuxPermissionsValid(linuxFilePermissions);
RunCommand($"install -m {linuxFilePermissions} /dev/null {path}", null, false, null);

// modify file owner if cert store file was created with sudo
if (ApplicationSettings.UseSudo)
Expand All @@ -258,6 +262,13 @@ public override void CreateEmptyStoreFile(string path)
}
}

public static void AreLinuxPermissionsValid(string permissions)
{
Regex regex = new Regex(LINUX_PERMISSION_REGEXP);
if (!regex.IsMatch(permissions))
throw new PEMException($"Invalid format for Linux file permissions. This value must be exactly 3 digits long with each digit between 0-7 but found {permissions} instead.");
}

private string ReplaceSpacesWithLF(string privateKey)
{
return privateKey.Replace(" RSA PRIVATE ", "^^^").Replace(" ", System.Environment.NewLine).Replace("^^^", " RSA PRIVATE ");
Expand Down
11 changes: 9 additions & 2 deletions PEMStoreSSH/RemoteHandlers/WinRMHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,15 @@
using System.Collections.Generic;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.Net;
using System.Text;

namespace Keyfactor.Extensions.Orchestrator.PEMStoreSSH.RemoteHandlers
{
class WinRMHandler : BaseRemoteHandler
{
WSManConnectionInfo connectionInfo { get; set; }

internal WinRMHandler(string server, string serverLogin, string serverPassword)
{
if (string.IsNullOrEmpty(server))
Expand All @@ -24,6 +27,11 @@ internal WinRMHandler(string server, string serverLogin, string serverPassword)
}

Server = server;
connectionInfo = new WSManConnectionInfo(new System.Uri($"{Server}/wsman"));
if (!string.IsNullOrEmpty(serverLogin))
{
connectionInfo.Credential = new PSCredential(serverLogin, new NetworkCredential(serverLogin, serverPassword).SecurePassword);
}
}

public override string RunCommand(string commandText, object[] parameters, bool withSudo, string[] passwordsToMaskInLog)
Expand All @@ -32,7 +40,6 @@ public override string RunCommand(string commandText, object[] parameters, bool

try
{
WSManConnectionInfo connectionInfo = new WSManConnectionInfo(new System.Uri($"{Server}/wsman"));
if (ApplicationSettings.UseNegotiateAuth)
{
connectionInfo.AuthenticationMechanism = AuthenticationMechanism.Negotiate;
Expand Down Expand Up @@ -146,7 +153,7 @@ public override void RemoveCertificateFile(string path)
RunCommand($@"rm ""{path}""", null, false, null);
}

public override void CreateEmptyStoreFile(string path)
public override void CreateEmptyStoreFile(string path, string linuxFilePermissions)
{
RunCommand($@"Out-File -FilePath ""{path}""", null, false, null);
}
Expand Down
3 changes: 2 additions & 1 deletion PEMStoreSSH/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
"UseSeparateUploadFilePath": "N",
"SeparateUploadFilePath": "/path/to/upload/folder/",
"UseNegotiateAuth": "N",
"UseSCP": "N"
"UseSCP": "N",
"DefaultLinuxPermissionsOnStoreCreation": "600"
}
Loading

0 comments on commit f2f46b2

Please sign in to comment.