Here’s a common scenario: using a network shared folder within an application. I see this in legacy .NET applications. There are two share types, NFS and SMB. NFS is more common in the Linux world; SMB rules the roost on the Windows side.
Pivotal Application Service customers use volume services to offer shares to a modern microservice. But it’s more challenging when you want to move legacy .NET apps to a cloud platform.
Ideally, you’d “bridge” the gap here with some minor re-design of the application, and native support from PAS. In a perfect world, it’s as simple as moving values that once lived in web.config to environment variables. Here, very little code has to change.
Network shares are less common in modern .NET. There are more cloud-native ways to approach this scenario. Message queues, caches, S3-compatible stores, and NoSQL stores are perfectly good options. These services offer resiliency, decoupled backing services, and statelessness. But that’s little consolation for our legacy scenario.
Both services are purpose-built for bringing a .NET application from IIS to the cloud world. PASW is how you can bring .NET Framework apps to a modern app platform. Steeltoe is a popular tool for building .NET microservices. (1.6 million downloads and counting!)
In this post, we’ll demonstrate how easy it is to implement
net use within a cloud-native .NET microservice.
We can start with a level-set on configuration and prerequisites. There are many ways to offer network shares. The ideas below can simply be used for comparison.
Our environment includes the PASW 2.3 tile (with an 1803 Windows Stemcell), Credhub runtime, and the PCF 2.3 Credhub service broker. We’ll use Visual Studio 2017 as the IDE, targeting either .NET Core 2.1 or .NET Framework 4.6 running on Windows.
Prerequisites & Assumptions
Windows SMB protocol runs on specific network ports. Ensure these ports are open, so your app can communicate with the server hosting the share, elsewhere on the network.
View the code
You can find the Visual Studio solution at https://github.com/pivotal/dotnet-smb-network-shares. It includes PowerShell scripts to create the tested environment.
Learn about the Steeltoe Framework
View samples, read the docs, and see the source code at https://steeltoe.io
Create the SMB Share
You’ll need an address for the share, plus credentials. Let’s run a Power Shell script to set things up. This was tested on Windows 2016 server, but is compatible with most modern Windows Server versions. (Note: this script must be run on the server as administrator, or with a highly privileged account.)
The script will create a new local user named
shareWriteUser, and then it will add that user to the local ‘Users’ group. From there, it will create a folder located at
c:\test_network_share (letting the default users and groups have access). Finally, it will share the folder, and give the new user write permission and read-access to the
The username and password of the local account with write permission is
shareWriteUser:thisIs1Pass!The network address of the new share is
\\<server IP>\test_network_share. One other quick note: PASW 1709 and 1803 stemcells require the IP address of the sharing server. They cannot resolve the machine’s name.
Create the Service in PAS
It’s not a good idea to hard code things like network addresses and account credentials. For the network address, you probably have separate development and production addresses. We want to build the app once and promote it through different environments without fiddling with config. Our app should hold a reference to the network address, but not the actual value. We can accomplish this with User Provided Services. This way, we bind the service to the app in the manifest. Then we use Steeltoe to parse the value and make it available within our app as a variable.
Because we use PAS, we have an added best practice to improve our security posture. We never want a password to be transmitted in clear text, or to be easily readable. We use the Credhub Service Broker to mitigate this risk. If your organization has a separation of duty between developers consuming a network share and the administrator that has access to the account creds, this will be a great fit!
Let’s create a powershell script that makes 2 services available in a given Org/Space. First, it will create a Credhub service instance, using the account values we just created in the previous step. Then, it will create a User Provided Service instance, that holds the network share address. If desired, you could easily distribute the two
cf commands to different teams who have access to each piece of info.
<SERVER_IP>in the above script. Replace this with the IP address of the server hosting the share. At this time machine names or FQDN are not supported.
Consuming the Bound Services with Steeltoe
It’s time to retrieve the values that were made available in the bindable services. First, we need to tell PAS to bind the services to our application upon deployment. This is accomplished in the manifest.yml file.
Now we have bound (or connected) the application to the services. Every time BOSH creates a new instance of our application, it will take care of the binding for us.
Next, we retrieve the values from the bound services. Steeltoe provides a very easy way of doing this through the
Steeltoe.Extensions.Configuration.CloudFoundry package. (For a complete example refer to the public repo.)
Let’s retrieve values from Credhub broker:
cfscript. We had to tell the Steeltoe CloudFoundry package to choose the correct service and the correct value saved within that service. This way, the app can have many other services bound to it without conflict.
Now that we have all needed values to put our network share to use.
The script below creates a
System.Net.NetworkCredentials object with needed values. Then it uses a
Steeltoe.Common.Net.WindowsNetworkFileShare object to establish the
net use connection. From here we can write files to the share!
Steeltoe.Common.Net package can only be used by an app running on Windows Server, not Linux. This is due to its use of the mpr.dll library. For a deeper look, check out the Steeltoe source here. For an explanation of mpr, check out this post.
Sign-Up for a Free Trial of PAS, and Start Using Steeltoe
To get more familiar with Steeltoe, head over to Pivotal Web Services(PWS) and create a free account. PWS is a hosted Cloud Foundry run by the experts at Pivotal. It’s a great place to get started with modern software development and cloud-native .NET. And thanks to all the sample apps created by the Steeltoe team, you can easily run starter scripts and see everything in action.
Using PCF? Then you can replay our tutorial in your own environment. When testing a network share on your foundation, take note of the pre-req’s and assumptions to make sure everything is configured properly. As a first step, simply push the demo app, and then working from there.
A note about Stemcells
Our opinions are usually a strong reason why so many prefer using PCF. As you explore the list of services Microsoft recommends turning to manual or disabling, you might find that our configuration of PASW stemcells doesn’t always match up. That's because we have the luxury of knowing exactly how the operating is going to be used and can lock down things further than their recommendations. Also don’t forget about the wonderful things BOSH does for us. There are a few cases where BOSH provides a similar service you might find in the base 1709 or 1803 operating system.
In the spirit of software-defined things, you can see exactly how we prep a PASW stemcell by reading the scripts. Compare the list of services in the script to Microsoft’s recommendation and you’ll have a [short] diff. Alternatively, if your PASW stemcells have been deployed with the ssh feature, you could run
cf ssh on a deployed app and then powershell
"Get-Service | Format-Table -Property Name
" to see a definitive list of the state of every service.
If you would like to see more about Microsoft’s point of view on the matter, they’ve posted an opinion in the Security Guidance area about what services should be disabled versus manual start. For consuming network shares we are specifically interested in NetBIOS service. This provides support for network name resolution. In our case (as you saw in the step-by-step and the Github repo) we’re going to need the IP address of the VM hosting the network share, and (when applicable) the creds to connect.