diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c76be1a..b4a8d915 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +v2.5.0 +- Add new optional custom field and config.json entries to supply a user id other than "root" for the user to "sudo into" when UseSudo = "Y". There is an optional config.json DefaultSudoImpersonatedUser that will be used at the orchestrator level, and an optional new store type custom field, SudoImpersonatedUser, that overrides the config.json setting for each certificate store. +- Modified the optional sudo command prefix to remove the "-i" option which was creating a new shell for the impersonated id (always root up until this release). Without this option the profile for the logged in user and not the impersonated user will be used when running commands. +- Added Regex checks for Discovery fields (file names, file extensions, and file paths) to enhance security. Only alpha numeric, "/", and "\" characters are allowed for these values. + v2.4.2 - Bug fix: Upgrade BouncyCastle.Cryptography to version 2.3.0 to allow for RFKDB HMAC-SHA-384 support diff --git a/README.md b/README.md index c523dbb1..132c8cf0 100644 --- a/README.md +++ b/README.md @@ -169,6 +169,7 @@ Please consult with your company's system administrator for more information on The Remote File Orchestrator Extension uses a JSON configuration file. It is located in the {Keyfactor Orchestrator Installation Folder}\Extensions\RemoteFile. None of the values are required, and a description of each follows below: { "UseSudo": "N", + "DefaultSudoImpersonatedUser": "", "CreateStoreIfMissing": "N", "UseNegotiate": "N", "SeparateUploadFilePath": "", @@ -177,7 +178,8 @@ The Remote File Orchestrator Extension uses a JSON configuration file. It is lo "DefaultOwnerOnStoreCreation": "" } -**UseSudo** (Applicable for Linux orchestrated servers only) - Y/N - Determines whether to prefix certain Linux command with "sudo". This can be very helpful in ensuring that the user id running commands over an ssh connection uses "least permissions necessary" to process each task. Setting this value to "Y" will prefix all Linux commands with "sudo" with the expectation that the command being executed on the orchestrated Linux server will look in the sudoers file to determine whether the logged in ID has elevated permissions for that specific command. For Windows orchestrated servers, this setting has no effect. Setting this value to "N" will result in "sudo" not being added to Linux commands. **Default value if missing - N**. +**UseSudo** (Applicable for Linux orchestrated servers only) - Y/N - Determines whether to prefix certain Linux command with "sudo". This can be very helpful in ensuring that the user id running commands over an ssh connection uses "least permissions necessary" to process each task. Setting this value to "Y" will prefix all Linux commands with "sudo" with the expectation that the command being executed on the orchestrated Linux server will look in the sudoers file to determine whether the logged in ID has elevated permissions for that specific command. For Windows orchestrated servers, this setting has no effect. Setting this value to "N" will result in "sudo" not being added to Linux commands. +**DefaultSudoImpersonatedUser** (Applicable for Linux orchestrated servers only) - Used in conjunction with UseSudo="Y", this optional setting can be used to set an alternate user id you wish to impersonate with sudo. If this option does not exist or is set to an empty string, the default user of "root" will be used. Any user id used here must have permissions to SCP/SFTP files to/from each certificate store location OR the SeparateUploadFilePath (see later in this section) as well as permissions to execute the commands listed in the "Security Considerations" section above. This value will be used for all certificate stores managed by this orchestrator extension implementation UNLESS overriden by the SudoImpersonatedUser certificate store type custom field setting described later in the Certificate Store Types section. **CreateStoreOnAddIfMissing** - Y/N - Determines, during a Management-Add job, if a certificate store should be created if it does not already exist. If set to "N", and the store referenced in the Management-Add job is not found, the job will return an error with a message stating that the store does not exist. If set to "Y", the store will be created and the certificate added to the certificate store. **Default value if missing - N**. **UseNegotiateAuth** (Applicable for Windows orchestrated servers only) – Y/N - Determines if WinRM should use Negotiate (Y) when connecting to the remote server. **Default Value if missing - N**. **SeparateUploadFilePath**(Applicable for Linux managed servers only) – Set this to the path you wish to use as the location on the orchestrated server to upload/download and later remove temporary work files when processing jobs. If set to "" or not provided, the location of the certificate store itself will be used. File transfer itself is performed using SCP or SFTP protocols (see FileT ransferProtocol setting). **Default Value if missing - blank**. @@ -211,6 +213,7 @@ When setting up the certificate store types you wish the Remote File Orchestrato *Custom Fields Tab:* - **Name:** LinuxFilePermissionsOnStoreCreation, **Display Name:** Linux File Permissions on Store Creation, **Type:** String, **Default Value:** none. This custom field is **not required**. If not present, value reverts back to the DefaultLinuxPermissionsOnStoreCreation setting in config.json (see Configuration File Setup section above). This value, applicable to certificate stores hosted on Linux orchestrated servers only, must be 3 digits all between 0-7. This represents the Linux file permissions that will be set for this certificate store if created via a Management Create job or a Management Add job where the config.json option CreateStoreOnAddIsMissing is set to "Y". - **Name:** LinuxFileOwnerOnStoreCreation, **Display Name:** Linux File Owner on Store Creation, **Type:** String, **Default Value:** none. This custom field is **not required**. If not present, value reverts back to the DefaultOwnerOnStoreCreation setting in config.json (see Configuration File Setup section above). This value, applicable to certificate stores hosted on Linux orchestrated servers only, represents the alternate Linux file owner/group that will be set for this certificate store if created via a Management Create job or a Management Add job where the config.json option CreateStoreOnAddIsMissing is set to "Y". If the group and owner need to be different values, use a ":" as a delimitter between the owner and group values, such as ownerId:groupId. Please confirm that the user name associated with this Keyfactor certificate store has valid permissions to chown the certificate file to this owner. +- **Name:** SudoImpersonatedUser, **Display Name:** Sudo Impersonated User Id, **Type:** String, **Default Value:** none. This custom field is **not required**. If not present, value reverts back to the DefaultSudoImpersonatedUser setting in config.json (see Configuration File Setup section above). Used in conjunction with UseSudo="Y", this optional setting can be used to set an alternate user id you wish to impersonate with sudo. If this option does not exist or is empty, and nothing is set for DefaultSudoImpersonatedUser in your config.json, the default user of "root" will be used. Any user id used here must have permissions to SCP/SFTP files to/from each certificate store location OR the SeparateUploadFilePath (see Configuration File Setup section above) as well as permissions to execute the commands listed in the "Security Considerations" section above. Entry Parameters Tab: - See specific certificate store type instructions below diff --git a/RemoteFile/ApplicationSettings.cs b/RemoteFile/ApplicationSettings.cs index 914e8fce..2b65a871 100644 --- a/RemoteFile/ApplicationSettings.cs +++ b/RemoteFile/ApplicationSettings.cs @@ -27,6 +27,7 @@ public enum FileTransferProtocolEnum private const string DEFAULT_LINUX_PERMISSION_SETTING = "600"; private const string DEFAULT_OWNER_SETTING = ""; + private const string DEFAULT_SUDO_IMPERSONATION_SETTING = ""; private static Dictionary configuration; @@ -36,6 +37,7 @@ public enum FileTransferProtocolEnum public static string SeparateUploadFilePath { get { return configuration.ContainsKey("SeparateUploadFilePath") ? AddTrailingSlash(configuration["SeparateUploadFilePath"]) : string.Empty; } } public static string DefaultLinuxPermissionsOnStoreCreation { get { return configuration.ContainsKey("DefaultLinuxPermissionsOnStoreCreation") ? configuration["DefaultLinuxPermissionsOnStoreCreation"] : DEFAULT_LINUX_PERMISSION_SETTING; } } public static string DefaultOwnerOnStoreCreation { get { return configuration.ContainsKey("DefaultOwnerOnStoreCreation") ? configuration["DefaultOwnerOnStoreCreation"] : DEFAULT_OWNER_SETTING; } } + public static string DefaultSudoImpersonatedUser { get { return configuration.ContainsKey("DefaultSudoImpersonatedUser") ? configuration["DefaultSudoImpersonatedUser"] : DEFAULT_SUDO_IMPERSONATION_SETTING; } } public static FileTransferProtocolEnum FileTransferProtocol { get diff --git a/RemoteFile/Discovery.cs b/RemoteFile/Discovery.cs index 69c33ac8..42df0c7c 100644 --- a/RemoteFile/Discovery.cs +++ b/RemoteFile/Discovery.cs @@ -15,6 +15,7 @@ using Keyfactor.Orchestrators.Common.Enums; using Microsoft.Extensions.Logging; +using Newtonsoft.Json; namespace Keyfactor.Extensions.Orchestrator.RemoteFile { @@ -57,7 +58,7 @@ public JobResult ProcessJob(DiscoveryJobConfiguration config, SubmitDiscoveryUpd ApplicationSettings.Initialize(this.GetType().Assembly.Location); certificateStore = new RemoteCertificateStore(config.ClientMachine, userName, userPassword, directoriesToSearch[0].Substring(0, 1) == "/" ? RemoteCertificateStore.ServerTypeEnum.Linux : RemoteCertificateStore.ServerTypeEnum.Windows); - certificateStore.Initialize(); + certificateStore.Initialize(ApplicationSettings.DefaultSudoImpersonatedUser); if (directoriesToSearch.Length == 0) throw new RemoteFileException("Blank or missing search directories for Discovery."); diff --git a/RemoteFile/InventoryBase.cs b/RemoteFile/InventoryBase.cs index 8d0fe637..3931e777 100644 --- a/RemoteFile/InventoryBase.cs +++ b/RemoteFile/InventoryBase.cs @@ -15,6 +15,7 @@ using Keyfactor.Extensions.Orchestrator.RemoteFile.Models; using Microsoft.Extensions.Logging; +using Newtonsoft.Json; namespace Keyfactor.Extensions.Orchestrator.RemoteFile { @@ -46,8 +47,13 @@ public JobResult ProcessJob(InventoryJobConfiguration config, SubmitInventoryUpd string storePassword = PAMUtilities.ResolvePAMField(_resolver, logger, "Store Password", config.CertificateStoreDetails.StorePassword); ApplicationSettings.Initialize(this.GetType().Assembly.Location); + dynamic properties = JsonConvert.DeserializeObject(config.CertificateStoreDetails.Properties.ToString()); + string sudoImpersonatedUser = properties.SudoImpersonatedUser == null || string.IsNullOrEmpty(properties.SudoImpersonatedUser.Value) ? + ApplicationSettings.DefaultSudoImpersonatedUser : + properties.SudoImpersonatedUser.Value; + certificateStore = new RemoteCertificateStore(config.CertificateStoreDetails.ClientMachine, userName, userPassword, config.CertificateStoreDetails.StorePath, storePassword, config.JobProperties); - certificateStore.Initialize(); + certificateStore.Initialize(sudoImpersonatedUser); certificateStore.LoadCertificateStore(certificateStoreSerializer, config.CertificateStoreDetails.Properties, true); List collections = certificateStore.GetCertificateChains(); diff --git a/RemoteFile/ManagementBase.cs b/RemoteFile/ManagementBase.cs index a6f9f438..5bb1d432 100644 --- a/RemoteFile/ManagementBase.cs +++ b/RemoteFile/ManagementBase.cs @@ -51,8 +51,13 @@ public JobResult ProcessJob(ManagementJobConfiguration config) string storePassword = PAMUtilities.ResolvePAMField(_resolver, logger, "Store Password", config.CertificateStoreDetails.StorePassword); ApplicationSettings.Initialize(this.GetType().Assembly.Location); + dynamic properties = JsonConvert.DeserializeObject(config.CertificateStoreDetails.Properties.ToString()); + string sudoImpersonatedUser = properties.SudoImpersonatedUser == null || string.IsNullOrEmpty(properties.SudoImpersonatedUser.Value) ? + ApplicationSettings.DefaultSudoImpersonatedUser : + properties.SudoImpersonatedUser.Value; + certificateStore = new RemoteCertificateStore(config.CertificateStoreDetails.ClientMachine, userName, userPassword, config.CertificateStoreDetails.StorePath, storePassword, config.JobProperties); - certificateStore.Initialize(); + certificateStore.Initialize(sudoImpersonatedUser); PathFile storePathFile = RemoteCertificateStore.SplitStorePathFile(config.CertificateStoreDetails.StorePath); diff --git a/RemoteFile/RemoteCertificateStore.cs b/RemoteFile/RemoteCertificateStore.cs index 8569f6fa..901c0b95 100644 --- a/RemoteFile/RemoteCertificateStore.cs +++ b/RemoteFile/RemoteCertificateStore.cs @@ -75,7 +75,7 @@ internal RemoteCertificateStore(string server, string serverId, string serverPas UploadFilePath = !string.IsNullOrEmpty(ApplicationSettings.SeparateUploadFilePath) && ServerType == ServerTypeEnum.Linux ? ApplicationSettings.SeparateUploadFilePath : StorePath; logger.LogDebug($"UploadFilePath: {UploadFilePath}"); - if (!IsStorePathValid()) + if (!IsValueSafeRegex(StorePath + StoreFileName)) { logger.LogDebug("Store path not valid"); string partialMessage = ServerType == ServerTypeEnum.Windows ? @"'\', ':', " : string.Empty; @@ -136,6 +136,14 @@ internal void Terminate() internal List FindStores(string[] paths, string[] extensions, string[] files, bool includeSymLinks) { logger.MethodEntry(LogLevel.Debug); + + if (!AreValuesSafeRegex(paths)) + throw new RemoteFileException(@"Invalid/unsafe directories to search value supplied. Only alphanumeric, /, and \ characters are allowed."); + if (!AreValuesSafeRegex(extensions)) + throw new RemoteFileException(@"Invalid/unsafe file extension value supplied. Only alphanumeric, /, and \ characters are allowed."); + if (!AreValuesSafeRegex(files)) + throw new RemoteFileException(@"Invalid/unsafe file name value supplied. Only alphanumeric, /, and \ characters are allowed."); + logger.MethodExit(LogLevel.Debug); if (DiscoveredStores != null) @@ -331,7 +339,7 @@ internal static PathFile SplitStorePathFile(string pathFileName) } } - internal void Initialize() + internal void Initialize(string sudoImpersonatedUser) { logger.MethodEntry(LogLevel.Debug); @@ -347,7 +355,19 @@ internal void Initialize() logger.MethodExit(LogLevel.Debug); } - private bool IsStorePathValid() + private bool AreValuesSafeRegex(string[] values) + { + bool valueIsSafe = true; + foreach(string value in values) + { + valueIsSafe = IsValueSafeRegex(value.Replace("*",String.Empty)); + if (!valueIsSafe) + break; + } + return valueIsSafe; + } + + private bool IsValueSafeRegex(string value) { logger.MethodEntry(LogLevel.Debug); @@ -355,7 +375,7 @@ private bool IsStorePathValid() logger.MethodExit(LogLevel.Debug); - return regex.IsMatch(StorePath + StoreFileName); + return regex.IsMatch(value); } private List FindStoresLinux(string[] paths, string[] extensions, string[] fileNames, bool includeSymLinks) diff --git a/RemoteFile/RemoteHandlers/SSHHandler.cs b/RemoteFile/RemoteHandlers/SSHHandler.cs index 495cafd8..e5440f5b 100644 --- a/RemoteFile/RemoteHandlers/SSHHandler.cs +++ b/RemoteFile/RemoteHandlers/SSHHandler.cs @@ -24,15 +24,15 @@ namespace Keyfactor.Extensions.Orchestrator.RemoteFile.RemoteHandlers class SSHHandler : BaseRemoteHandler { private ConnectionInfo Connection { get; set; } - private bool IsStoreServerLinux { get; set; } - + private string SudoImpersonatedUser { get; set; } private SshClient sshClient; - internal SSHHandler(string server, string serverLogin, string serverPassword, bool isStoreServerLinux) + internal SSHHandler(string server, string serverLogin, string serverPassword, bool isStoreServerLinux, string sudoImpersonatedUser) { _logger.MethodEntry(LogLevel.Debug); Server = server; + SudoImpersonatedUser = sudoImpersonatedUser; IsStoreServerLinux = isStoreServerLinux; List authenticationMethods = new List(); @@ -98,13 +98,18 @@ public override string RunCommand(string commandText, object[] arguments, bool w { _logger.MethodEntry(LogLevel.Debug); - string sudo = $"sudo -i -S "; + string sudo = $"sudo -S "; string echo = $"echo -e '\n' | "; try { if (withSudo && IsStoreServerLinux) - commandText = sudo + commandText; + { + if (string.IsNullOrEmpty(SudoImpersonatedUser)) + commandText = sudo + commandText; + else + commandText = sudo + $"-u {SudoImpersonatedUser}" + " " + commandText; + } if (IsStoreServerLinux) { @@ -219,7 +224,6 @@ public override void UploadCertificateFile(string path, string fileName, byte[] if (!string.IsNullOrEmpty(ApplicationSettings.SeparateUploadFilePath) && IsStoreServerLinux) { - //RunCommand($"cat {uploadPath} > {path}/{fileName}", null, ApplicationSettings.UseSudo, null); RunCommand($"tee {path}/{fileName} < {uploadPath} > /dev/null", null, ApplicationSettings.UseSudo, null); RunCommand($"rm {uploadPath}", null, ApplicationSettings.UseSudo, null); } @@ -243,7 +247,8 @@ public override byte[] DownloadCertificateFile(string path) SplitStorePathFile(path, out altPathOnly, out altFileNameOnly); downloadPath = ApplicationSettings.SeparateUploadFilePath + altFileNameOnly; RunCommand($"cp {path} {downloadPath}", null, ApplicationSettings.UseSudo, null); - RunCommand($"chown {Connection.Username} {downloadPath}", null, ApplicationSettings.UseSudo, null); + if (string.IsNullOrEmpty(SudoImpersonatedUser)) + RunCommand($"chown {Connection.Username} {downloadPath}", null, ApplicationSettings.UseSudo, null); } bool scpError = false; diff --git a/RemoteFile/config.json b/RemoteFile/config.json index 24999a06..3e638d79 100644 --- a/RemoteFile/config.json +++ b/RemoteFile/config.json @@ -1,9 +1,10 @@ { "UseSudo": "N", + "DefaultSudoImpersonatedUser": "", "CreateStoreIfMissing": "N", "UseNegotiate": "N", "SeparateUploadFilePath": "", "FileTransferProtocol": "SCP", "DefaultLinuxPermissionsOnStoreCreation": "600", - "DefaultOwnerOnStoreCreation": "" + "DefaultOwnerOnStoreCreation": "" } \ No newline at end of file diff --git a/integration-manifest.json b/integration-manifest.json index 641a20a9..bb423a33 100644 --- a/integration-manifest.json +++ b/integration-manifest.json @@ -68,6 +68,14 @@ "DependsOn": "", "Type": "String", "DefaultValue": "" + }, + { + "Name": "SudoImpersonatingUser", + "DisplayName": "Sudo Impersonating User", + "Required": false, + "DependsOn": "", + "Type": "String", + "DefaultValue": "" } ], "EntryParameters": [] @@ -110,6 +118,14 @@ "Type": "String", "DefaultValue": "" }, + { + "Name": "SudoImpersonatingUser", + "DisplayName": "Sudo Impersonating User", + "Required": false, + "DependsOn": "", + "Type": "String", + "DefaultValue": "" + }, { "Name": "IsTrustStore", "DisplayName": "Trust Store", @@ -190,6 +206,14 @@ "DependsOn": "", "Type": "String", "DefaultValue": "" + }, + { + "Name": "SudoImpersonatingUser", + "DisplayName": "Sudo Impersonating User", + "Required": false, + "DependsOn": "", + "Type": "String", + "DefaultValue": "" } ], "EntryParameters": [] @@ -232,6 +256,14 @@ "Type": "String", "DefaultValue": "" }, + { + "Name": "SudoImpersonatingUser", + "DisplayName": "Sudo Impersonating User", + "Required": false, + "DependsOn": "", + "Type": "String", + "DefaultValue": "" + }, { "Name": "SeparatePrivateKeyFilePath", "DisplayName": "Separate Private Key File Location", @@ -280,6 +312,14 @@ "DependsOn": "", "Type": "String", "DefaultValue": "" + }, + { + "Name": "SudoImpersonatingUser", + "DisplayName": "Sudo Impersonating User", + "Required": false, + "DependsOn": "", + "Type": "String", + "DefaultValue": "" } ], "EntryParameters": [] @@ -322,6 +362,14 @@ "Type": "String", "DefaultValue": "" }, + { + "Name": "SudoImpersonatingUser", + "DisplayName": "Sudo Impersonating User", + "Required": false, + "DependsOn": "", + "Type": "String", + "DefaultValue": "" + }, { "Name": "WorkFolder", "DisplayName": "Location to use for creation/removal of work files", diff --git a/readme_source.md b/readme_source.md index 574a4ca5..452661dc 100644 --- a/readme_source.md +++ b/readme_source.md @@ -68,6 +68,7 @@ Please consult with your company's system administrator for more information on The Remote File Orchestrator Extension uses a JSON configuration file. It is located in the {Keyfactor Orchestrator Installation Folder}\Extensions\RemoteFile. None of the values are required, and a description of each follows below: { "UseSudo": "N", + "DefaultSudoImpersonatedUser": "", "CreateStoreIfMissing": "N", "UseNegotiate": "N", "SeparateUploadFilePath": "", @@ -76,7 +77,8 @@ The Remote File Orchestrator Extension uses a JSON configuration file. It is lo "DefaultOwnerOnStoreCreation": "" } -**UseSudo** (Applicable for Linux orchestrated servers only) - Y/N - Determines whether to prefix certain Linux command with "sudo". This can be very helpful in ensuring that the user id running commands over an ssh connection uses "least permissions necessary" to process each task. Setting this value to "Y" will prefix all Linux commands with "sudo" with the expectation that the command being executed on the orchestrated Linux server will look in the sudoers file to determine whether the logged in ID has elevated permissions for that specific command. For Windows orchestrated servers, this setting has no effect. Setting this value to "N" will result in "sudo" not being added to Linux commands. **Default value if missing - N**. +**UseSudo** (Applicable for Linux orchestrated servers only) - Y/N - Determines whether to prefix certain Linux command with "sudo". This can be very helpful in ensuring that the user id running commands over an ssh connection uses "least permissions necessary" to process each task. Setting this value to "Y" will prefix all Linux commands with "sudo" with the expectation that the command being executed on the orchestrated Linux server will look in the sudoers file to determine whether the logged in ID has elevated permissions for that specific command. For Windows orchestrated servers, this setting has no effect. Setting this value to "N" will result in "sudo" not being added to Linux commands. +**DefaultSudoImpersonatedUser** (Applicable for Linux orchestrated servers only) - Used in conjunction with UseSudo="Y", this optional setting can be used to set an alternate user id you wish to impersonate with sudo. If this option does not exist or is set to an empty string, the default user of "root" will be used. Any user id used here must have permissions to SCP/SFTP files to/from each certificate store location OR the SeparateUploadFilePath (see later in this section) as well as permissions to execute the commands listed in the "Security Considerations" section above. This value will be used for all certificate stores managed by this orchestrator extension implementation UNLESS overriden by the SudoImpersonatedUser certificate store type custom field setting described later in the Certificate Store Types section. **CreateStoreOnAddIfMissing** - Y/N - Determines, during a Management-Add job, if a certificate store should be created if it does not already exist. If set to "N", and the store referenced in the Management-Add job is not found, the job will return an error with a message stating that the store does not exist. If set to "Y", the store will be created and the certificate added to the certificate store. **Default value if missing - N**. **UseNegotiateAuth** (Applicable for Windows orchestrated servers only) – Y/N - Determines if WinRM should use Negotiate (Y) when connecting to the remote server. **Default Value if missing - N**. **SeparateUploadFilePath**(Applicable for Linux managed servers only) – Set this to the path you wish to use as the location on the orchestrated server to upload/download and later remove temporary work files when processing jobs. If set to "" or not provided, the location of the certificate store itself will be used. File transfer itself is performed using SCP or SFTP protocols (see FileT ransferProtocol setting). **Default Value if missing - blank**. @@ -110,6 +112,7 @@ When setting up the certificate store types you wish the Remote File Orchestrato *Custom Fields Tab:* - **Name:** LinuxFilePermissionsOnStoreCreation, **Display Name:** Linux File Permissions on Store Creation, **Type:** String, **Default Value:** none. This custom field is **not required**. If not present, value reverts back to the DefaultLinuxPermissionsOnStoreCreation setting in config.json (see Configuration File Setup section above). This value, applicable to certificate stores hosted on Linux orchestrated servers only, must be 3 digits all between 0-7. This represents the Linux file permissions that will be set for this certificate store if created via a Management Create job or a Management Add job where the config.json option CreateStoreOnAddIsMissing is set to "Y". - **Name:** LinuxFileOwnerOnStoreCreation, **Display Name:** Linux File Owner on Store Creation, **Type:** String, **Default Value:** none. This custom field is **not required**. If not present, value reverts back to the DefaultOwnerOnStoreCreation setting in config.json (see Configuration File Setup section above). This value, applicable to certificate stores hosted on Linux orchestrated servers only, represents the alternate Linux file owner/group that will be set for this certificate store if created via a Management Create job or a Management Add job where the config.json option CreateStoreOnAddIsMissing is set to "Y". If the group and owner need to be different values, use a ":" as a delimitter between the owner and group values, such as ownerId:groupId. Please confirm that the user name associated with this Keyfactor certificate store has valid permissions to chown the certificate file to this owner. +- **Name:** SudoImpersonatedUser, **Display Name:** Sudo Impersonated User Id, **Type:** String, **Default Value:** none. This custom field is **not required**. If not present, value reverts back to the DefaultSudoImpersonatedUser setting in config.json (see Configuration File Setup section above). Used in conjunction with UseSudo="Y", this optional setting can be used to set an alternate user id you wish to impersonate with sudo. If this option does not exist or is empty, and nothing is set for DefaultSudoImpersonatedUser in your config.json, the default user of "root" will be used. Any user id used here must have permissions to SCP/SFTP files to/from each certificate store location OR the SeparateUploadFilePath (see Configuration File Setup section above) as well as permissions to execute the commands listed in the "Security Considerations" section above. Entry Parameters Tab: - See specific certificate store type instructions below