In this scenario we’re assuming we can recompile the application, and will dynamically retrieve passwords from the vault whenever needed.
using Thycotic.SecretServer.Sdk.Extensions.Integration.Clients;
using Thycotic.SecretServer.Sdk.Extensions.Integration.Models;
using Thycotic.SecretServer.Sdk.Infrastructure.Models;
Alternatively, you can instantiate the objects and let Visual Studio add the references for you.
You need to instantiate a new SecretServerClient object to interact with the SDK. Below is a sample code:
var client = new SecretServerClient();
//configure if not configured
client.Configure(new ConfigSettings
{
SecretServerUrl = string,
RuleName = string,
RuleKey = string,
CacheStrategy= CacheStrategy.enum,
CacheAge= int,
ResetToken= string
});
The code above will register the integrated client with Secret Server. Below is an explanation of the properties of the client’s ConfigSettings:
ConfigSettings
is an objectSecretServerUrl
is the base URL for your Secret Server (if you have a Load Balancer then it should be the load balanced URL)RuleName
is the name of the rule we created earlierRuleKey
is the Key we generated, can be NULL if no keyCacheStrategy
is how the SDK will cache requests. This is an enum with four options:CacheThenServer
CacheThenServerAllowExpired
(This will allow fallback; in case Secret Server isn’t available and the cache is expired, the SDK will still use the cache until it can contact Secret Server and prime the cache)Never
ServerThenCache
(This mode is for redundancy since it will fall back to cache in case Secret Server isn’t available)CacheAge
is how long the cache is valid before it expires in minutesResetToken
is a random string to revoke clients and reinitialize themOnce the client is configured for the first time, a series of encrypted configuration files are created. By default they will be saved in the current working directory of your application. This path can be customized with the SecretServerSdkConfigDirectory AppSetting.
If using the .NET Standard version of the SDK, these config files are protected by an encryption key. It is saved in the current user’s home directory by default, but this path can also be customized with the SecretServerSdkKeyDirectory AppSetting if necessary.
If you need to change your configuration, change your reset token and the SDK will reinitialize the config files. Otherwise, the SDK will not reconfigure itself as long as it can still access and decrypt the config files. Calls to client.Configure() are ignored if the reset token remains the same and the client has already been configured.
Now we can use the client to get a Secret, Token, or a Secret field from Secret Server, and feed that to our application.
var password = client.GetSecretField(<SECRET ID>,"password"); //replace <SECRET ID>
The code above will retrieve a password from Secret Server, which we can then pass to a connection string or anywhere a password is needed.
You can call the GetSecret();
method on the client object to get the full Secret object, and then access the items property which holds a collection of the Secret fields and their values. How you access these values is up to you, but you can use Linq to query what you’re looking for, e.g.
var secret = client.GetSecret(<SECRET ID>); //replace <SECRET ID>
var server = secret.Items.First(x => x.Slug == "server").ItemValue;
var username = secret.Items.First(x => x.Slug == "username").ItemValue;
var password = secret.Items.First(x => x.Slug == "password").ItemValue;
var database = secret.Items.First(x => x.Slug == "database").ItemValue;
and then use these variables to build a connection string:
SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(GetConnectionString())
{
ConnectionString = $"server={server};user id={username};password={password};initial catalog={database}"
};
Here is the complete code sample:
using System;
using System.Linq;
using Thycotic.SecretServer.Sdk.Extensions.Integration.Clients;
using Thycotic.SecretServer.Sdk.Extensions.Integration.Models;
using Thycotic.SecretServer.Sdk.Infrastructure.Models;
using System.Data.SqlClient;
namespace SDK.Integration
{
class Program
{
static void Main(string[] args)
{
var url = ""; //replace with Secret Server URL
var ruleName = ""; //replace with SDK rule name
var ruleKey = ""; //replace with on boarding key
var cacheAge = int; //replace with number for cache age
var secretId = int; //replace with Secret ID
var client = new SecretServerClient();
//configure if not configured
client.Configure(new ConfigSettings
{
SecretServerUrl = url,
RuleName = ruleName,
RuleKey = ruleKey,
CacheStrategy= CacheStrategy.CacheThenServerAllowExpired,
CacheAge= cacheAge, //in minutes
ResetToken= "Token"
});
var secret = client.GetSecret(secretId);
var server = secret.Items.First(x => x.Slug == "server").ItemValue;
var username = secret.Items.First(x => x.Slug == "username").ItemValue;
var password = secret.Items.First(x => x.Slug == "password").ItemValue;
var database = secret.Items.First(x => x.Slug == "database").ItemValue;
//connection string example
SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(GetConnectionString())
{
ConnectionString = $"server={server};user id={username};password={password};initial catalog={database}"
};
Console.WriteLine(builder.ConnectionString);
Console.ReadKey();
}
private static string GetConnectionString()
{
return "Server=(local);Integrated Security=SSPI;" +
"Initial Catalog=AdventureWorks";
}
}
}
In this scenario we’re assuming we can’t recompile the application, or prefer not to. The use case is as follows:
The SDK will allow us to pull data from Secret Server and inject it in the config file.
Note that the injected data is not available in Application_Start, because this is a HTTP Intercept module it will not have ran yet.
Open you web.config file in your preferred code editor and add the inside your appSettings tag following:
<appSettings>
<add key="tss:CacheAge" value="<cache-age>" />
<add key="tss:CacheStrategy" value="<cache-strategy>" />
<add key="tss:SecretServerUrl" value="<your-secret-server-url>" />
<add key="tss:RuleName" value="<rule-name>" />
<add key="tss:RuleKey" value="<rule-key>" />
<add key="tss:ResetToken" value="<reset-token>" />
</appSettings>
and add the following:
<system.webServer>
<module>
<remove name="ThycoticInterceptModule" ></remove>
<add name="ThycoticInterceptModule"
type="Thycotic.SecretServer.Sdk.Extensions.Integration.HttpModule.Modules.ThycoticInterceptModule,Thycotic.SecretServer.Sdk.Extensions.Integration.HttpModule" ></add>
Our section should look like this:
<system.webServer>
<validation validateIntegratedModeConfiguration="false" ></validation>
<modules>
<remove name="ThycoticInterceptModule" ></remove>
<add name="ThycoticInterceptModule"
type="Thycotic.SecretServer.Sdk.Extensions.Integration.HttpModule.Modules.ThycoticInterceptModule,Thycotic.SecretServer.Sdk.Extensions.Integration.HttpModule" ></add>
<remove name="TelemetryCorrelationHttpModule" ></remove>
<add name="TelemetryCorrelationHttpModule"
type="Microsoft.AspNet.TelemetryCorrelation.TelemetryCorrelationHttpModule, Microsoft.AspNet.TelemetryCorrelation"
preCondition="integratedMode,managedHandler" ></add>
<remove name="ApplicationInsightsWebTracking" ></remove>
<add name="ApplicationInsightsWebTracking"
type="Microsoft.ApplicationInsights.Web.ApplicationInsightsHttpModule, Microsoft.AI.Web"
preCondition="managedHandler" ></add>
</modules>
</system.webServer>
Important: You may need to add a binding redirect if you run into:
Message: System.IO.FileLoadException : Could not load file or assembly 'System.Runtime.InteropServices.RuntimeInformation, Version=0.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)
Simply add the following to your web.config file
<dependentAssembly>
<assemblyIdentity name="System.Runtime.InteropServices.RuntimeInformation" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" ></assemblyIdentity>
<bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" ></bindingRedirect>
</dependentAssembly>
Match the version number with what you have installed on your system
To replace plaintext credentials in your web.config file we simply use string interpolation to replace the hard-coded values with Secret Server values as shown below
Example old ConnectionString:
<connectionStrings>
<clear ></clear>
<add
name="AdventureWorks2014ConnectionString"
connectionString="Data Source=sql01.domain.com;Initial Catalog=AdventureWorks2014;Persist Security Info=True;User ID=sa;Password=SgW#5)zLpo($@d"
providerName="System.Data.SqlClient"
></add>
</connectionStrings>
New connection string with Secret Server SDK:
<connectionStrings>
<clear ></clear>
<add
name="AdventureWorks2014ConnectionString"
connectionString="Data Source=${server};Initial Catalog=${database};Persist Security Info=True;User ID=${username};Password=${password}?3112"
providerName="System.Data.SqlClient"
></add>
</connectionStrings>
Where the 3112
is the Secret Id preceded by ?
This class has the following methods:
This method doesn’t have an overload. Calling it destroys the SDK’s cache of Secrets. The SDK configuration is still retained.
settings
Type: Object
Key value pairs to configure the SDK
force (optional)
Type: boolean
Default: false
Forces the SDK to reconfigure itself
This method returns a Secret object based on the REST secret model
id
Type: int32
The secret id needed to retrieve the Secret
This method gets a specific field from the Secret instead of returning the whole object
id
Type: int32
The Secret Id needed to retieve the Secret
fieldslug
Type: String
Slug identifier for the Secret field e.g. password
This method returns a REST API token from Secret Server, after authenticating with the configured SDK account.
Just like GetAccessToken but asynchronous.
To get the command-line interface SDK Client tool check out our knowledge base article, SDK Downloads. This tool is not required to use the SDK NuGet packages.
The SDK Client and SDK NuGet packages are two separate projects with separate versioning. We actively work to maintain feature parity between the two projects, but at times their features may differ.