SecureTokens PowerShell Module
Overview
I wrote this module as a way to manage passwords and application api tokens used by my scripts. Rather than save them un-encrypted or un-obfuscated where anyone and everyone could either read them or figure them out, this leverages the built-in features of the PowerShell secure-string (non-portable) or cert document encryption (portable).
Is it absolutely secure? No, not really. But the non-portable Token is limited to decoding only by the user who creates them on the machine they're created on; and the portable Token requires the correct certificate installed in the correct certificate store. So that helps. A little.
Yes, you read that right:
- the non-portable files created on 1 system by 1 user are useless on another system or for another user. Only the user who creates the files can use them on the machine where they are created.
- the portable files created on 1 system by 1 user requires the correct certificate installed to the correct certificate store (so CurrentUser\My if it will be used by a user or LocalMachine\My if the script will be run "by the computer")
Security Note
Sigh.
Clearing the current session command history is simple enough, and I've been doing that since way early in development.
BUT, PSReadline saves its history in a text file (run (Get-PSReadLineOption).HistorySavePath
to check it), and it doesn't provide an interface to delete 1 item. So, the
Add-SecureToken
command, complete with the text of the Token, exists in that
file. Big :(
I now have a fix (the file is UTF-8, btw) - but I consider it beta at this point. I don't want to go and start deleting data all willy-nilly without people expecting it!
Besides, it slows down the Add-SecureToken function a bit (more as the history file grows).
So, if you want to try the history scrub, Add-SecureToken now has a -ScrubPSReadlineHistory
switch. This will remove ALL instances of Add-SecureToken where it's the first
item on a line.
I've also added a -SecureToken
parameter that takes a SecureString (or prompts
for one). It's a bit of a kludge at the moment - with some back and forth
en/de/encryption - I have plans to rework a couple things in the near(-ish) future,
so I fig this config can stay for a bit.
Note
Huge shout out to Boe Prox for the CMS message encryption! https://mcpmag.com/articles/2017/10/05/encrypting-data-with-powershell-cmdlets.aspx
SecureTokens are portable, baybee!!
Folder for Tokens
I default the tokens to the user's AppData\Roaming folder:
C:\Users\username\AppData\Roaming\SecureTokens
Each file is a simple text file using the token name as the filename and the encrypted string as the body of the file. You can change the filename, but don't change the content!
Since these are files, you can delete and rename them via any of the usual Windows file management tools. I've also added some low-key rename and remove functions to help and make it a bit more self-contained.
I provide functions to manage certs (create-, export-, import-) ... but not
delete!! You can use PowerShell's certificate PSDrive for that (either
cert:\CurrentUser\My
or cert:\LocalMachine\My
) or the MMC.exe Certificates
snap-in (the My
store is called Personal\Certificates
there ... cuz
consistency).
I've also added a Default Certificate option so you can save a default cert to use for all new Tokens. Setting a default cert will then force all new Tokens to be portable (i.e., certificate encrypted) until the default cert is 'unset'. You can still use the -Certificate switch of the Add-SecureToken function to over-ride the default cert, but you won't be able to create non-portable Tokens unless you clear the default cert. See the Set-STDefaultCertificate function for details. (Oh, and yes, the default certificate config can be saved to disk for posterity and re-use).
Usage
Naturally, the module should go where PowerShell modules go, either in the
C:\Users\YourUser\Documents\WindowsPowerShell\Modules
(for you personally)
or the C:\Windows\system32\WindowsPowerShell\v1.0\Modules
(for everyone)
folder. (Yes, there are other options, but these are generally the main ones).
You can then import this module via the PowerShell native Import-Module command:
import-module SecureTokens
From there you can:
Command | Description |
---|---|
Set-SecureTokenFolder | Set (and save) the location of the files that hold secured tokens |
Get-SecureTokenFolder | Returns the path to the tokens folder |
Add-SecureToken | Add a token to the secured tokens file |
Get-SecureToken | Returns the Token for the specified Name |
Get-SecureTokenList | Returns the names of all tokens |
Get-SecureTokenHelp | List commands available in the SecureTokens Module |
Remove-SecureToken | Deletes an existing Token |
Rename-SecureToken | Renames an existing Token to the specified Name |
New-STEncryptionCertificate | Creates a new document encryption certificate |
Find-STEncryptionCertificate | Returns certificates available for encryption |
Export-STEncryptionCertificate | Exports a document encryption certificate for later import |
Import-STEncryptionCertificate | Imports a document encryption certificate for use |
Get-STDefaultCertificate | Returns the current Default Certificate |
Set-STDefaultCertificate | Set (and save) the default certificate used to encrypt tokens |
The module will automatically show these commands on load (it runs
Get-SecureTokenHelp) unless you use the -ArgumentList $true
option of
the Import-Module command (the first parameter of the module is 'Quiet').
import-module SecureTokens -ArgumentList $true
On first run, the default location for tokens will NOT be created. You will
want to fix that with the Set-SecureTokenFolder
command (examples below).
Examples
Initialization
Importing the module
PS C:\Scripts> Import-Module SecureTokens
Attempting to load SecureTokens config file...
Loaded config file
Path to SecureTokens (C:\Users\user\AppData\Roaming\SecureTokens) is valid
Getting available functions...
Command Description
------- -----------
Add-SecureToken Add a token to the secured tokens file
Export-STEncryptionCertificate Exports a document encryption certificate for later import
Find-STEncryptionCertificate Returns certificates available for encryption
Get-SecureToken Returns the Token for the specified Name
Get-SecureTokenFolder Returns the path to the tokens folder
Get-SecureTokenHelp List commands available in the SecureTokens Module
Get-SecureTokenList Returns the names of all tokens
Get-STDefaultCertificate Returns the current Default Certificate
Import-STEncryptionCertificate Imports a document encryption certificate for use
New-STEncryptionCertificate Creates a new document encryption certificate
Remove-SecureToken Deletes an existing Token
Rename-SecureToken Renames an existing Token to the specified Name
Set-SecureTokenFolder Set (and save) the location of the files that hold secured tokens
Set-STDefaultCertificate Set (and save) the default certificate used to encrypt tokens
Working with the Tokens folder
To set the default location:
PS C:\Scripts> Set-SecureTokenFolder -Default -Clobber
To set the your own location:
PS C:\Scripts> Set-SecureTokenFolder -Folder 'C:\Scripts\Tokens' -Clobber
To set a temporary location (maybe alternate tokens? test vs prod?):
PS C:\Scripts> Set-SecureTokenFolder -Folder 'C:\Scripts\ProdTokens'
To check the current token location
PS C:\Scripts> Get-SecureTokenFolder
Folder Exists
------ ------
C:\Users\user\AppData\Roaming\SecureTokens True
Adding Tokens
Saving a token called Aida
PS C:\Scripts> Add-SecureToken -Name 'Aida' -Token '1234-5678-9'
Saved token to C:\Users\user\AppData\Roaming\SecureTokens\Aida.txt
PS C:\Scripts> Add-SecureToken -Name 'Aida' -Token '1234-5678-9' -Certificate 'cn=mycert@localhost'
Saved token to C:\Users\user\AppData\Roaming\SecureTokens\Aida.txt
PS C:\Scripts> Add-SecureToken -Name 'Aida' -Token '1234-5678-9' -Certificate 'cn=mycert@localhost'
Saved token to C:\Users\user\AppData\Roaming\SecureTokens\Aida.txt
PS C:\Scripts> Add-SecureToken -Name 'Aida' -SecureToken $(Read-Host -AsSecureString)
Saved token to C:\Users\user\AppData\Roaming\SecureTokens\Aida.txt
PS C:\Scripts> Add-SecureToken -Name 'Aida'
Enter the Token: ****
Saved token to C:\Users\user\AppData\Roaming\SecureTokens\Aida.txt
Listing tokens
Listing all tokens
PS C:\Scripts> Get-SecureTokenList
Aida
Candy
Myne
Myne2
Filtering saved tokens (regex!)
All that start with C
PS C:\Scripts> Get-SecureTokenList -Filter C
Candy
All that have a y in the name
PS C:\Scripts> Get-SecureTokenList -Filter "\w+y"
Myne
Myne2
All that have a digit in the name
PS C:\Scripts> Get-SecureTokenList -Filter "\w+\d"
Myne2
Using Tokens
Viewing a token
PS C:\Scripts> Get-SecureToken -Name 'Aida'
Name Token
---- -----
Aida 1234-5678-9
Using a token in a script
$Token = (Get-SecureToken -Name SlackAPIToken).Token
if ($Token) {
Add-SlackMessage -Channel 'Public' -Message 'Hello World!' -Token $Token
} else {
"No token found"
}
Modifying Tokens
Renaming a token
PS C:\Scripts> Rename-SecureToken -Name 'Aida' -NewName 'Adia'
Name NewName
---- -----
Aida Adia
Deleting a token
PS C:\Scripts> Remove-SecureToken -Name 'Aida' -Confirm
Confirm
Are you sure you want to perform this action?
Performing the operation "Remove File" on target "C:\Users\youruser\AppData\Roaming\SecureTokens\Aida.txt".
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "Y"): y
Name Deleted
---- -------
Aida True
Working with Certs
Creating a new certificate (defaults to 2048-bit and 100 year expiration)
PS C:\Scripts> New-STEncryptionCertificate -Subject 'portableenc@localhost'
Thumbprint Expires Subject
---------- ------- -------
D4035B0B69002C00D2AD124EC2CC8FC0D93F0B4B 01/09/2119 CN=portableenc@localhost
Creating a new certificate (4096-bit and 100 days expiration)
PS C:\Scripts> New-STEncryptionCertificate -Subject 'portableenc@localhost' -HighKeyLength -Days 100
Thumbprint Expires Subject
---------- ------- -------
D058A8397FDEF8ECB378406861FA7E6A64C2B1DC 04/19/2019 CN=portableenc@localhost
Viewing existing document encryption certificates
PS C:\Scripts> Find-STEncryptionCertificate
Thumbprint Expires Subject
---------- ------- -------
EEA15A54F3B50E60E42E95F765CFC8D22D5E98A5 01/12/2019 CN=testenc3@localhost
2F6883858A09215233C2D80690707AC7CD36EAF2 04/12/2019 CN=testenc2@localhost
D058A8397FDEF8ECB378406861FA7E6A64C2B1DC 04/19/2019 CN=poratbleenc@localhost
51382C455E6590B00526AB99E5FDB5F63D1C53ED 01/02/2119 CN=testenc@localhost
D4035B0B69002C00D2AD124EC2CC8FC0D93F0B4B 01/09/2119 CN=poratbleenc@localhost
Export a certificate
PS C:\Scripts> Export-STEncryptionCertificate -Thumbprint D058A8397FDEF8ECB378406861FA7E6A64C2B1DC -OutPath C:\Scripts\
cmdlet Export-STEncryptionCertificate at command pipeline position 1
Supply values for the following parameters:
(Type !? for Help.)
Password: ****
Thumbprint Status Filename
---------- ------ --------
D058A8397FDEF8ECB378406861FA7E6A64C2B1DC Success C:\Scripts\D058A8397FDEF8ECB378406861FA7E6A64C2B1DC.pfx
(you can, of course, rename this file)
Export all certificates
PS C:\Scripts> Find-STEncryptionCertificate | Export-STEncryptionCertificate -OutPath .
cmdlet Export-STEncryptionCertificate at command pipeline position 2
Supply values for the following parameters:
(Type !? for Help.)
Password: ****
Thumbprint Status Filename
---------- ------ --------
EEA15A54F3B50E60E42E95F765CFC8D22D5E98A5 Success C:\Scripts\tcerts\EEA15A54F3B50E60E42E95F765CFC8D22D5E98A5.pfx
2F6883858A09215233C2D80690707AC7CD36EAF2 Success C:\Scripts\tcerts\2F6883858A09215233C2D80690707AC7CD36EAF2.pfx
D058A8397FDEF8ECB378406861FA7E6A64C2B1DC Success C:\Scripts\tcerts\D058A8397FDEF8ECB378406861FA7E6A64C2B1DC.pfx
51382C455E6590B00526AB99E5FDB5F63D1C53ED Success C:\Scripts\tcerts\51382C455E6590B00526AB99E5FDB5F63D1C53ED.pfx
D4035B0B69002C00D2AD124EC2CC8FC0D93F0B4B Success C:\Scripts\tcerts\D4035B0B69002C00D2AD124EC2CC8FC0D93F0B4B.pfx
Import a certificate
PS C:\Scripts> Import-STEncryptionCertificate -Fullname .\D058A8397FDEF8ECB378406861FA7E6A64C2B1DC.pfx
cmdlet Import-STEncryptionCertificate at command pipeline position 1
Supply values for the following parameters:
(Type !? for Help.)
Password: ****
Thumbprint Expires Subject
---------- ------- -------
D058A8397FDEF8ECB378406861FA7E6A64C2B1DC 04/19/2019 CN=portableenc@localhost
Import all the certificate files
PS C:\Scripts> dir *.pfx | Import-STEncryptionCertificate
cmdlet Import-STEncryptionCertificate at command pipeline position 2
Supply values for the following parameters:
(Type !? for Help.)
Password: ****
Thumbprint Expires Subject
---------- ------- -------
2F6883858A09215233C2D80690707AC7CD36EAF2 04/12/2019 CN=testenc2@localhost
51382C455E6590B00526AB99E5FDB5F63D1C53ED 01/02/2119 CN=testenc@localhost
D058A8397FDEF8ECB378406861FA7E6A64C2B1DC 04/19/2019 CN=portableenc@localhost
D4035B0B69002C00D2AD124EC2CC8FC0D93F0B4B 01/09/2119 CN=portableenc@localhost
EEA15A54F3B50E60E42E95F765CFC8D22D5E98A5 01/12/2019 CN=testenc3@localhost
(notice the 2 portableenc
certs ... bad juju)