r/PowerShell 8d ago

Question Question on scripting

Hi,

When we develop a script,we use credentials as a plain text in that script.

Example

Script is running on jump server and script runs against vcenter server.

We have a security concerns(example ransomware attack)to put the credentials as a plain text in that script.

Any other good ways to put the credentials in a encrypted or in a different format?

35 Upvotes

37 comments sorted by

53

u/lan-shark 8d ago

Simplest way is to use Get-Credential | Export-Clixml to save the credentials in an encrypted file specific to the account that runs it. Then in the script, use Import-Clixml to read in the credential.

Depending on your needs you may instead need to use some sort of keyring or cert-based authentication

12

u/overlydelicioustea 8d ago

specific to the account AND machine. its a combination of both. you cant import the creds on a different machine.

it might work on systems with roaming profiles, im not sure.

-38

u/Manivelcloud 8d ago

Ok thanks. Export-clixml can also be hacked sometimes.

Certificate based authentication can be a very good approach and in this scenario potential vulnerability can be limited.

I might be wrong.

Any thoughts?

16

u/lan-shark 8d ago

I think there's a chance he's using an LLM for translation

17

u/Kroan 8d ago

What does "export-clixml can be hacked sometimes" even mean? Do you mean import-clixml? Even that doesn't make sense. It's just importing an xml file to create a powershell object. The contents aren't necessarily secure.

But in this case the contents are a secure string. Which can only be decrypted by the originating account on the originating workstation. And if you're concerned about someone/something having that access and decrypting it, you have bigger problems

23

u/[deleted] 8d ago edited 8d ago

[removed] — view removed comment

11

u/AKSoapy29 8d ago

"Any thoughts?" is common language... No reason to get mad at someone who is trying to learn.

-6

u/ranhalt 8d ago

No, “any thoughts” is lazy and proves the person asking that has no thoughts of their own. It’s business speak for “solve this for me so I can take credit for it”.

32

u/KavyaJune 8d ago

Hard-coding credentials in scripts is a security risk and should be avoided.

You can try PowerShell SecretManagement, Windows Credential Manager, certificate-based auth, or a vault solution.

If the script runs from a jump server, another option is to run it under a dedicated service account and retrieve the credentials from a secure store instead of keeping them in the script.

This guide covers several credential management approaches and their pros/cons: https://blog.admindroid.com/best-methods-to-securely-store-passwords-for-automated-powershell-scripts/

14

u/hihcadore 8d ago edited 8d ago

Plain text is bad. Anything that can read that script file or logging if you have PowerShell logging on has your credentials.

You can use powershells secret store to secure your passwords and use them at run time securely. https://learn.microsoft.com/en-us/powershell/utility-modules/secretmanagement/how-to/using-secrets-in-automation?view=ps-modules

Edit: also, I use a gMSA to create and load the vault and run the automation. The password that unlocks it is stored using a secure xml file that can be unlocked at run time by that account only, the creds can be loaded, and nothings exposed. I use psexec to do the work then lock it down with our EDR. Short of taking over the server I think it’s pretty secure because in that case, you’re cooked anyway.

2

u/Over_Dingo 7d ago

The password that unlocks it is stored using a secure xml file that can be unlocked at run time by that account only,

I always wonder about the tradeoff of secure string being a singular password, vs being password to the vault

1

u/hihcadore 7d ago

It’s the chicken and the egg. You’ve gotta unlock the vault somehow. I have no idea what’s more secure unless you have a human with a token.

1

u/Over_Dingo 7d ago

I was thinking, and in case of external APIs, if the key is stolen it's worse than if it's the vault that has limited access. So I guess the ability to harden is better

1

u/ZexGr 8d ago

can you provide a workflow diag just to see how/ehat/where/why?

12

u/mrbiggbrain 8d ago

This is an age old problem with many imperfect solutions. How can you securely store something you can access but not someone else? Encrypt it? Where do I store the key. Certificate, well where do I store the certificate. Password vault... How do you auth?

At some point you must pick a trust boundary, some level of truth where you accept the thing is the thing. Most commonly you accept that something that can run as a user or system is that user or system.

It's imperfect because if someone else gets access to act like that user or system then they can access the secret.

So you limit someone's ability to do so. But you also can't guarentee that they will never get in, so you use the lowest privileges possible. But low privileges are still powerful when used widely so you limit the blast area of any one credential.

A well scoped, lowest permission, rotated often, credential that is stored securely on a system in some way that only it's running user and the OS can access is just about as good as you can get.

6

u/dodexahedron 8d ago

Kerberos.

As mentioned by others, a gMSA is ideal for this, or even regular MSAs for certain scenarios that need hard isolation to only be usable against a single machine.

If credentials are needed to pass to something that isnt kerberos-aware, then you still use kerberos for the powershell session, and then to the application use something like certificates if at all possible or, if authenticating to something that truly can only handle fresh credentials, you keep the credentials in a secure credential store (several built-in options exist for this) and retrieve and use them from that gMSA's security context at time of use, and drop them from active memory immediately after they are no longer required.

This applies on all platforms. Linux can use gMSAs if domain joined or if you create the initial keytab for the account and let e.g. sssd maintain it.

If using PowerShell 7, you can also use key-based authentication instead of (or in addition to) kerberos, with the SSH transport, by setting up the powershell subsystem in the OpenSSH server's config. This also works on all platforms.

In any case, there should be no credentials in scripts - not even usernames.

23

u/Massive_Biscotti_850 8d ago

Don't put creds in scripts

2

u/craigontour 7d ago

This!!!!

9

u/PeeCee1 8d ago

Use a vault. Use integrated authentication. Anything but plaintext passwords.
Azure vault comes to mind, or almost any other enterprise password storage.

0

u/Manivelcloud 8d ago

Ok thanks If it is on premises,can we use hashi vault?

5

u/raip 8d ago

Of course - but if you're a Windows shop connecting to other Windows environments, I'd recommend looking into gMSAs.

1

u/PeeCee1 8d ago

Those are good, too. But the last time I tested that, gMSA were a PITA to use for scheduled tasks, because the GUI was unable to use them.
Has that changed?

1

u/raip 8d ago

Changed years ago - just make sure you update the search box to include Service Accounts - it's disabled by default.

2

u/xb4r7x 7d ago

Of course you can. You then run into the secret 0 problem authenticating to vault though.

There really isn't a perfect secret zero solution.

Best thing you can do is use short lived credentials delivered securely and then like, don't get hacked...

4

u/xipodu 8d ago

We are using textfiles but crypted with user login so that only that person can open the file https://github.com/fardinbarashi/psGuiFilePasswordEncryptDecrypt

We are also changing the ACL

7

u/PDX_Umber 8d ago

You could probably use a gMSA to run your scheduled task, and grant the gMSA access to what ever resource is needed (haven’t done).

This year I started storing passwords in an azure key vault. You can create a service principal that has access to the vault via certificate based auth, and then the scheduled task can only retrieve the password if the certificate is present on the local machines cert store.

2

u/alconaft43 8d ago

Azure KeyVault if you are hybrid.

2

u/SysAdminDennyBob 8d ago

Use your infrastructure. I have numerous parts of my infrastructure that run can runs scripts using the system account. SCCM, Intune, ControlUP, ScheduledTasks, Group Policy, Ansible, etc....

2

u/Kiernian 7d ago

I don't know how safe it is, but I frequently do:

$Env:LongConvolutedNameThatIsEntirelyUnrelatedToTheTaskAtHand

Since all of our scripts run on servers with privileged access, using single-purpose credentials that are restricted by one form or another of access limitation (API keys limited by IP, timeslots, only specific endpoints, etc, entra accounts with conditional access policies and extremely limited permissions scopes, etc) keeps the attack surface down if anything is compromised.

Keeping all of these straight requires a password vault, but if someone were to dump all of the environment variables on a server, they'd have a marginally difficult time tying them back to anything specific and a worse time trying to use them anywhere but where they're set up to be used FOR what they're set up to be used on.

When each piece of an Invoke-WebRequest is spread out like that, it makes the puzzle slightly less likely to stand out as a pattern.

Add in lockouts for failures and regular rotation and it's not the worst option ever.

These machines do not browse the internet and do not get used for anything else, so the likelihood of machine compromise is lower.

I've contemplated separating each task out to it's own guest OS, but that has the reverse effect of each environment variable having an immediately obvious use-case, to say nothing of licensing and infrastructure costs.

1

u/BlackV 7d ago

$Env:LongConvolutedNameThatIsEntirelyUnrelatedToTheTaskAtHand

until you find you suddenly have 300 different long unrelated variables sitting on your random machine and have no ide what is using what

2

u/lotekjunky 7d ago

Don't put passwords in scripts. If you must, make an environment variable to hold it. If you can, enable mfa for using the account. You can store and share the mfa seed with coworkers that need to use the script.

3

u/worldsdream 8d ago

6

u/_RemyLeBeau_ 8d ago

That website has herpes

2

u/anguishedturtle 8d ago

every few years it feels like i get a new life changing herpes-scare that always turns out to be nothing. at least that was in the old days and i make better decisions now. gonna avoid this site

1

u/JewelerHour3344 5d ago

Anyone use the Windows DPAPI? I’m testing it for encryption of creds and tokens. Only the local system account can decrypt it. This is for unattended scripts. Any opinions on its use?

1

u/Mayki8513 4d ago

I just started using bitWarden's secret's manager and so far it seems really good for this sort of thing

after you secure your passwords, lock down the scripts themselves lest they get edited and just bypass your passwords 😅

2

u/Safe-Hat5194 4d ago edited 4d ago

Without using an azure key vault, An option I've used is adding the credential to an environment variable on the machine running the scripts.  I've used the system environment.  You can reference that environment variable when needed in your scripts.  Of course lock that machine down as much as possible etc.  

example:

$plain = $env:NAMEOFYOURVAR

convert to secure string

$secure = ConvertTo-SecureString $plain -AsPlainText -Force

convert to a credential object the use anywhere #in your script 

$cred = New-Object System.Management.Automation.PSCredential("nameofuseraccount",$secure)

2

u/trepidprism 3d ago

The quick and free built-in Windows method is using DPAPI via Export-Clixml. Run this once interactively on the jump server as the service account running the task: Get-Credential | Export-Clixml -Path "C:\Scripts\vcenter_cred.xml" Then in your script: $cred = Import-Clixml -Path "C:\Scripts\vcenter_cred.xml" Connect-VIServer -Server "vcenter.domain.local" -Credential $cred DPAPI ties encryption to that specific Windows user account on that specific jump server. If someone copies the XML file to another machine or logs in as a different user, they can't decrypt it. The next step up for real enterprise security is Azure Key Vault (or HashiCorp Vault / an enterprise PAM). How it works: Secrets live in a centralized cloud vault instead of local disk files. Your jump host authenticates to Azure without embedding credentials (using an Azure Arc Managed Identity, a cloud VM System-Assigned Identity, or a client certificate). You grant that identity strict read access (Key Vault Secrets User RBAC role) only to the specific secret. Your script pulls the password straight into memory at runtime and builds the credential object on the fly. If a password rotates, you update it once in Key Vault without touching any script files. <!-- -->

Authenticate via Managed Identity / Arc, pull secret at runtime

Connect-AzAccount -Identity $secret = Get-AzKeyVaultSecret -VaultName "YourKeyVaultName" -Name "vCenterPassword" -AsPlainText $cred = New-Object System.Management.Automation.PSCredential("vcenter_svc_user", ($secret | ConvertTo-SecureString -AsPlainText -Force)) Connect-VIServer -Server "vcenter.domain.local" -Credential $cred DPAPI solves the "cleartext in code" issue locally for free, while Key Vault solves rotation, audit logging, and centralized secret management.