HOWTO – Set up a Windows 2012 R2 Remote Desktop Services (RDS) farm

This article outlines one possible way to set-up a remote desktop services farm in Windows 2012 R2.

Before Windows 2012 came on the scene, setting up remote desktop services involved a lot of manual labour, installing several components managed in a heap of management snap-ins.

When designing Windows 2012, Microsoft has put a lot of effort in centralising all the configuration panels for a Remote Desktop Services deployment in one central management console, they even have implemented deployment wizards to make the whole installation process easy to handle.

A Microsoft Windows 2012/R2 Remote Desktop Services deployment is divided into several roles which can be installed on separate servers.  In a full deployment we can have the following roles:

Remote Desktop Connection Broker:
Connects or reconnects a client device to RemoteApp programs, session-based desktops and virtual desktops.

Remote Desktop WebAccess:

Enables users to connect to resources provided by session collections and virtual desktop collections by using the Start menu or a web browser.

Remote Desktop Session Host:

A server running the Remote Desktop Protocol Server.  This allows the server to run RemoteApp and session-based desktops.

Remote Desktop Gateway:

Enables authorized users to connect to virtual desktops, RemoteApp programs, and session-based desktops on the corporate network or over the Internet.

In below procedures we’ll be performing a lab tutorial to install a Windows 2012 Remote Desktop Services Farm consisting of the following servers and roles:

RDSBROKER01:

Remote Desktop Services connection broker and web resource server

RDSBROKER02:

Remote Desktop Services connection broker (provided for high availability)

RDS01:

Remote Desktop Services session host server

RDS02:

Remote Desktop Services session host server

RDSGWY01:

Remote Desktop Services gateway server

Log in to your first server (RDSBROKER01) and open the Server Manager console.

For organisational purposes we will create a server group to hold all of our Remote Desktop Services servers, this is not required for the deployment though.

In the Server Manager, click on ‘Create a Server Group’.


1. Select the Active Directory tab.

2. Enter ‘RD’ as search string in the Name box.

3. Click on ‘Find Now’.

4. Ctrl select all servers that you want to add to this group.

5. Click the arrow to add them to the group.

In the Server Manager a new node will appear with the group name that we created, which holds the servers that we have added to it.

We can now start deploying our Remote Desktop Services roles to these servers.

Click on ‘Manage’, then click on ‘Add Roles and Features’.

Select ‘Next’ on the ‘Before You Begin’ screen.

On the ‘Installation Type screen, select ‘Remote Desktop Services Installation’, then click ‘Next’.

Select ‘Standard deployment’ and click next.  (quick start deployment is only for proof of concept environments and should never be used out of lab environments)

Remote Desktop Services can be deployed as VDI solution or as Session-Based solution.  In our lab tutorial we will deploy the Session-Based deployment.

The ‘Role Services’ window will show us which Remote Desktop Services roles will be deployed in our installation, the displayed roles are the minimum roles required for a Remote Desktop Services installation.

In the next screen we need to assign a server to the first role, the RD Connection Broker Role, that will be deployed in our Remote Desktop Services Farm.

In the next screen we need to assign a server to the RD Web Access role, select a server from the server pool tab and add this to the selected window.

Next we need to assign servers to our third role, the RD Session Host roles, this role wil allmost always have multiple servers assigned to it for high availability purposes.

The next screen in our wizard will show an overview of the selections that we made during the wizard, which are now ready for deployment.  Click ‘Deploy’ to start the installation process.

The progress of the Remote Dekstop Services deployment installation can be monitored on the ‘Completion’ screen.

After the installation you will see a new node in the server manager called Remote Desktop Services.

All configuration management for the whole farm and it’s actions, like publishing RemoteApp or Session-Based desktops, or adding more RDS host servers, configure High Availability, will happen from within this centralised management console.

Next we need to ensure that all communication within our Remote Desktop Services farm is secure.

For this purpose, all communication will be encrypted using SSL/TLS protocols.

Before we can use these security protocols, we will need to establish a PKI (Public Key Infrastructure) in our domain environment.

See the next Article:  HOWTO – Set up a two tier PKI Hierarchy Deployment.

Advertisement

HOWTO – use openssl on linux – a bunch of useful openssl commands to use

Generate CSRs, Certificates, Private Keys and do other miscellaneous tasks:

Generate a new private key and Certificate Signing Request

  • openssl req -out CSR.csr -new -newkey rsa:2048 -nodes -keyout privateKey.key


Generate a self-signed certificate

  • openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout privateKey.key -out certificate.crt


Generate a certificate signing request (CSR) for an existing private key

  • openssl req -out CSR.csr -key privateKey.key -new


Generate a certificate signing request based on an existing certificate

  • openssl x509 -x509toreq -in certificate.crt -out CSR.csr -signkey privateKey.key


Remove a passphrase from a private key

  • openssl rsa -in privateKey.pem -out newPrivateKey.pem

Checking Using OpenSSL:

If you need to check the information within a Certificate, CSR or Private Key, use these commands.


Check a Certificate Signing Request (CSR)

  • openssl req -text -noout -verify -in CSR.csr


Check a private key

  • openssl rsa -in privateKey.key -check


Check a certificate

  • openssl x509 -in certificate.crt -text -noout


Check a PKCS#12 file (.pfx or .p12)

  • openssl pkcs12 -info -in keyStore.p12

Debugging Using OpenSSL:
If you are receiving an error that the private doesn’t match the certificate or that a certificate that you installed to a site is not trusted, try one of these commands.


Check an MD5 hash of the public key to ensure that it matches with what is in a CSR or private key

  • openssl x509 -noout -modulus -in certificate.crt | openssl md5
  • openssl rsa -noout -modulus -in privateKey.key | openssl md5
  • openssl req -noout -modulus -in CSR.csr | openssl md5


Check an SSL connection. All the certificates (including Intermediates) should be displayed

Converting Using OpenSSL:

These commands allow you to convert certificates and keys to different formats to make them compatible with specific types of servers or software. For example, you can convert a normal PEM file that would work with Apache to a PFX (PKCS#12) file and use it with Tomcat or IIS.

Convert a DER file (.crt .cer .der) to PEM

  • openssl x509 -inform der -in certificate.cer -out certificate.pem


Convert a PEM file to DER

  • openssl x509 -outform der -in certificate.pem -out certificate.der


Convert a PKCS#12 file (.pfx .p12) containing a private key and certificates to PEM

  • openssl pkcs12 -in keyStore.pfx -out keyStore.pem -nodes


You can add -nocerts to only output the private key or add -nokeys to only output the certificates.
Convert a PEM certificate file and a private key to PKCS#12 (.pfx .p12)

  • openssl pkcs12 -export -out certificate.pfx -inkey privateKey.key -in certificate.crt -certfile CACert.crt

HOWTO – Set up Raspberry IP Camera on Synology Surveillance station

Let’s get ready to use the Raspberry Pi as low-cost Full HD surveillance IP camera.

First download your copy of the Raspberry IP Camera software at http://ronnyvdbr.github.io/RaspberryIPCamera/

After downloading, write the image to SD card with the win32diskimager software.

Put your SD card into the Raspberry, boot it up, scan your network for the right IP address of the IP Camera as it will be autoconfigured by DHCP.


Set up the Camera for usage with Synology Surveillance station:

1. Log in to the web interface with admin as username and raspberry as password.

2. Click the camera settings entry on the menu bar.

3. Set the camera to it’s highest resolution, after that set the format to H264 (Streamable over RTSP), after that, click apply on the bottom of the page.

Now add the IP Camera to your Synology Surveillance Station:

1. Open your Synology Surveillance Station web interface, and open your IP Camera control panel.

2. Select ‘add’, then select ‘Add Camera’.

3. Select ‘complete’ and click ‘next’.

4. Name your Camera, fill in the IP address, set the port number to 8554, select User Define as brand, and set the source path to / (note that the password for this is blank, so do not enter a password)

Howto – Compile & Install Gstreamer on Raspberry Pi

Prerequisite

sudo apt-get install libglib2.0-dev bison flex libtool 
autoconf automake autopoint gtk-doc-tools libx264-dev liborc-0.4-dev 
nasm yasm cmake libmicrohttpd-dev libjansson-dev libnice-dev librtmp-dev

Download these

* gstreamer/gstreamer

* gstreamer/gst-plugins-base

* gstreamer/gst-plugins-good

* gstreamer/gst-plugins-bad

* gstreamer/gst-plugins-ugly

from GStreamer source, at the time writing this post, the latest version I use is 1.4.1

For gst-plugins-basegst-plugins-good and gst-plugins-ugly, simply

./autogen.sh
make -j
sudo make install

For gst-plugins-bad, there’s a little problem during normal installation. In old times, gst-plugins-gl was required for gst-plugins-bad and now it is merged into gst-plugins-bad, at least they claim so, but somehow there’s some bug in there at this moment, which causegst-plugins-bad could not find gst-plugins-gl and gst-plugins-gl cannot be installed due to the fact that the author thinks there’s no need to install it since it has been merged intogst-plugins-bad.

So we need some hack for this. Fortunately, this thread has already worked it out. Follow those steps and you should get rid off the trouble.

Edit environment variable

in ~/.bashrc add a line

export LD_LIBRARY_PATH=/usr/local/lib

and reload bash file:

exec bash

Test command:

If you’ve installed rpicamsrc:

gst-launch-1.0 rpicamsrc bitrate=2000000 rotation=90 ! video/x-h264,width=1080,height=760,framerate=25/1 ! h264parse ! udpsink host=localhost port=5000

else:

raspivid  -t 0 -h 720 -w 1080 -fps 25 -b 2000000 -o - | gst-launch-1.0 -v fdsrc ! h264parse !  rtph264pay config-interval=1 pt=96 ! gdppay ! tcpserversink host=0.0.0.0 port=5000

Howto – Stream HTML5 video – H264 encoded video encapsulated in MP4 from the Raspberry Pi to any web browser

At the time of writing I’m developing a Bootstrap/Web interface for the Raspberry Pi camera module, to transform a Raspberry Pi into an easily configurable IP Camera.

As we all come to know it, the GPU module which comes with the Raspberry Pi supports several hardware assisted encoding formats.

Two of the more popular format’s include H264, – and MJPEG encoding, my little project consists only of these two encoding formats.

In the IP camera which i’m developing I wanted to make both standards easily available for external connection like video recording software/hardware, this while preserving the capability to display the video feed of the camera on the web interface itself.

To display an MJPEG feed on a web page, this is very easy, as you can just insert an <img> tag in your html page which links up to your MJPEG stream and you’re off, upon loading your web page this feed will play.

Example:

<img src=”http://raspberryip/?action=stream&#8221; alt=””/>

Displaying the raw H264 feed from the Raspberry IP camera on a web page was a lot more difficult.

We need to make use of the HTML5 video tag to display H264 encoded video on a web page.

The H264 encoded data stream which comes off the Raspberry Pi’s GPU is a raw bytestream and cannot be delivered by direct means to the web page, we need to encapsulate the stream in MP4 container format to subsequently deliver it over HTTP to the web browser’s video tag for playing.

If we split this whole task in bite size chunks we can distract a few distinct pieces:

  1. Getting the raw H264 data feed from the Raspberry Pi’s GPU.
  2. Wrap the raw H264 data feed in MP4 container chunk format.
  3. Transfer these MP4 container chunks to the browser on demand.

1. Getting the raw H264 data stream from the GPU is well documented and easy.

You can use the raspivid tool (which comes with the Raspberry Pi) to dump out the raw H264 data stream.   To dump this stream to standard output you can use below command:

$ raspivid -w 1920 -h 1080 -fps 30 -pf high -n -t 0 -o -

2. Getting this raw output into MP4 container format was a bit more difficult, and involves the use of gstreamer.  Gstreamer is like a swiss army knife if you want to transcode media data, and is highly modular, it supports a lot of media data types. 

Raspbian already contains a version of gstreamer in it’s repository, and is installable with aptitude.

To install gstreamer:

$ sudo apt-get -y install gstreamer1.0

And afterwards use gstreamer to transcode our stream:

$ gst-launch-1.0 -e -q fdsrc fd=0 ! video/x-h264,width=1920,height=1080,framerate=30/1,stream-format=byte-stream ! h264parse ! mp4mux streamable=true fragment-duration=10 presentation-time=true ! filesink location=/dev/stdout'

3. Transferring our containerized MP4 data stream to the browser involves on demand transfer over http to the video element in our browser.   For this we can use a small python script, which runs a simple web server to transfer our transcoded data to the browser.  Upon get request from our browser our MP4 will be send to the browser, and the browser will play the video data through the HTML5 video tag.

import subprocess # for piping
from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler

class RequestHandler(BaseHTTPRequestHandler):
    def _writeheaders(self):
        self.send_response(200) # 200 OK http response
        self.send_header('Content-type', 'video/mp4')
        self.end_headers()

    def do_HEAD(self):
        self._writeheaders()

    def do_GET(self):
        self._writeheaders()

        DataChunkSize = 10000

        command = '(echo "--video boundary--"; raspivid -w 1920 -h 1080 -fps 30 -pf high -n -t 0 -o -;) | gst-launch-1.0 -e -q fdsrc fd=0 ! video/x-h264,width=1920,height=1080,framerate=30/1,stream-format=byte-stream ! h264parse ! mp4mux streamable=true fragment-duration=10 presentation-time=true ! filesink location=/dev/stdout'
        print("running command: %s" % (command, ))
        p = subprocess.Popen(command, stdout=subprocess.PIPE, bufsize=-1, shell=True)

        print("starting polling loop.")
        while(p.poll() is None):
            print "looping... "
            stdoutdata = p.stdout.read(DataChunkSize)
            self.wfile.write(stdoutdata)

        print("Done Looping")

        print("dumping last data, if any")
        stdoutdata = p.stdout.read(DataChunkSize)
        self.wfile.write(stdoutdata)

if __name__ == '__main__':
    serveraddr = ('', 8765) # connect to port 8765
    srvr = HTTPServer(serveraddr, RequestHandler)
    srvr.serve_forever()

Let’s say we save this script to a file called httpserver, then we need to run this file with python:

$ python httpserver

The only thing that remains now is to build a simple web page with the HTML5 video element which will connect to this web server for the video feed.

$ <!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>HTML5 Video Tag Test</title>
</head>

<video width="1920" height="1080" controls>
  <source src="http://192.168.20.147:8765" type="video/mp4">

Your browser does not support the video tag.
</video>

<body>
</body>
</html>

Howto – Build a bluetooth Music Streamer

Almost all my activities (for example cooking, working on projects or playing games) have one thing in common: There’s music playing in the background.

Usually this is some sort of FM radio running a local radio channel. The drawbacks are obvious: You have no control over what music is runing and the audio quality is far from great.

I started to ponder what to do about it. My requirements were simple:

  • Choose the music myself: These days, most of what i listen to is either internet radio, or a music streaming service like Spotify or Google Play Music
  • Reasonable quality: I am not an audiophile, but at least i do not want to have audible artifacts or noise when i walk past an antenna or something
  • Easy installation: I have no intent to run speaker wires to every room
  • Price: I dont want to spend hundreds of euros and for example buy Sonos speakers for all my rooms. At 230 Euros a piece, this would become really expsive really fast

Hardware

My system is built on the basis of bluetooth speakers.

I chose to use the Xiaomi Square Box for this, because it is quite cheap. But any bluetooth speaker would do. Of course the Xiaomi Box can not compete with expensive speakers like the Sonos or Bose systems, but at around 20 Euros incl. shipping, it is not bad. I even got one of these on a sale for 13 Euros incl. shipping.

The speakers have a builtin battery, so you could carry it around the house. But since i planned on just throwing this on a cupboard, i run it of a cheap phone charger.

Next thing i bought was a bluetooth dongle, which i plugged into my home server. In my case, the home server is an HP Microserver Gen8. But you could easily run this of a Rasperry Pi.

Software

For this to work, you need any current linux distribution. I amrunning Archlinux, because i like to tinker with new stuff, receive updates fast and take care of my system.

If you run some form of Ubuntu or Debian, for example Raspbian on a Raspi, the steps will be roughly the same. But since Ubuntu uses upstart where archlinux is based on systemd, you will have to improvise on that point.

To play my music, i currently use the Music Player Deamon, short MPD. The get support for spotify and the likes, i plan to change to mopidy. I just have not gotten around to it yet.

I use openHAB for my home automation, so the controls for the music will also be implemented there.

Steps to make it happen

Connecting bluetooth devices

Use bluetoothctl to turn on your bluetooth controller, pair, trust and connect to the speakers. Make sure to replace the mac address of your speakers.

% bluetoothctl
[bluetooth]# power on
Changing power on succeeded
[bluetooth]# scan on Device A0:E9:DB:51:3B:C5 Mi Bluetooth Speaker [bluetooth]# pair A0:E9:DB:51:3B:C5 ...
[bluetooth]# trust A0:E9:DB:51:3B:C5 ...
[bluetooth]# pair A0:E9:DB:51:3B:C5 ...

Make sure your bluetooth controller is powered on after a reboot. On archlinux, this is done using a simple udev rule in /etc/udev/rules.d/20-bluetooth.rules containing this:

# Set bluetooth power up 
ACTION=="add", SUBSYSTEM=="bluetooth", KERNEL=="hci[0-9]*", RUN+="/usr/bin/hciconfig %k up"

Make sure everything after ACTION is one line.

Pulseaudio

Enable pulseaudio as a permanently running service (not socket activated) and start it.

% systemctl --user enable pulseaudio.service 
% systemctl --user start pulseaudio.service

Also make sure your user session is started on boot.

% sudo systemctl enable user@1000.service

Where 1000 is the user id of your user. You can get this id by running the program “id” as the corresponding user:

% id uid=1000(tlan) gid=1000(tlan) groups=1000(tlan),7(lp),10(wheel),91(video),92(audio),1001(download) (If groups does not contain audio) 
% sudo gpasswd -a <username> audio

This is also the time to make sure your user is part of the group “audio” and if not, add him.

If everything went according to plan, pulseaudio should have automatically added your bluetooth devices as sinks. You can check using “pacmd”

% pacmd list-sinks 
1 sink(s) available.
* index: 1 name: <bluez_sink.A0_E9_DB_51_3B_C5>
driver: <module-bluez5-device.c>
flags: HARDWARE DECIBEL_VOLUME LATENCY FLAT_VOLUME
state: SUSPENDED
suspend cause: IDLE
priority: 9030
volume: front-left: 51773 / 79% / -6.14 dB, front-right: 51773 / 79% / -6.14 dB
balance 0.00
base volume: 65536 / 100% / 0.00 dB
volume steps: 65537
muted: no
... properties:
bluetooth.protocol = "a2dp_sink"
device.description = "Mi Bluetooth Speaker"
device.string = "A0:E9:DB:51:3B:C5"
... (Optional, to set an upper limit for the volume)
% pacmd set-sink-volume
bluez_sink.A0_E9_DB_51_3B_C5 50000

By setting the sink volume a bit under the maximum value of 65k and controlling the volume in my player software independently from pulseaudio, i effectively limit the maximum volume that can be set to not overload my speakers.

Add the line “load-module module-switch-on-connect” to /etc/pulse/default.pa to make sure pulseaudio automatically connects to your speakers after a reboot.

You should now be able to play music and hear it out of your bluetooth speakers. If you do not specify a sink, pulseaudio will output everything using the default sink.

MPD

I installed MPD and created the configuration files for each room in ~/.config/mpd:

% touch kitchen.{conf,database,log,pid}

Set up everything needed in the conf file. Make sure the files, especially the pid file, are unique for each configuration.  Change the paths to music and playlists to your needs

music_directory "/media/virtual/Music/mp3"
playlist_directory "/media/virtual/Music/playlist"
db_file "~/.config/mpd/kitchen.database"
log_file "~/.config/mpd/kitchen.log"
pid_file "~/.config/mpd/kitchen.pid"

port "6600"

audio_output {
type "pulse"
name "Kitchen"
sink "bluez_sink.A0_E9_DB_51_3B_C5"
}

Every instance of MPD has its own database. If you dont want this, see the Archwiki: Music Player Daemon – Satellite_setup.

The I created a special parameterized systemd unit in ~/.config/systemd/user/mpd@.service to run multiple MPDs with a custom configuration each

Description=Music Player Daemon
After=network.target sound.target

[Service] ExecStart=/usr/bin/mpd --no-daemon %h/.config/mpd/%I.conf

[Install] WantedBy=default.target

Then, have systemd reload config files, enable an instance of this configuration and start it

% systemctl --user daemon-reload 
% systemctl --user enable mpd@kitchen
% systemctl --user start mpd@kitchen

You should now be able to play music using mpd to your bluetooth speakers. Use any MPD client to test this.

OpenHAB

OpenHAB comes with a binding for MPD. Bindings are plugins, that extend openHABs features for IoT devices. I use the binding to start/stop the music and control the volume.

Unfortunately, the plugin does not have features builtin to control playlists. So i decided just to use the exec-Binding, which allows you to run system commands, and the mpc client to load playlists.

Alternatively, i could have used a WebView, to display some sort of Webinterface for MPD in an iframe. But since right now, i only need to choose between two different playlists, i did not bother.

OpenHAB users will be familiar with the configuration layout, so i will just post the config files here and not go into much detail:

 % cat Music.items configurations/items raspberrypi Switch Mpd_Kitchen_StartStop "Start/Stop" (Kitchen,Radio) { mpd="ON:kitchen:play, OFF:kitchen:stop" } Dimmer Mpd_Kitchen_VolumeControl "Volume [%d%%]" (Kitchen,Radio) { mpd="INCREASE:kitchen:volume_increase, DECREASE:kitchen:volume_decrease, PERCENT:kitchen:volume" } String Mpd_Kitchen_Channel_Selection "Sender" (Kitchen,Radio) { autoupdate="false" } String Mpd_Kitchen_Channel (Kitchen,Radio) { exec=">[CLEAR:mpc -h tlan-server.local -p 6600 clear] >[1LIVE:mpc -h tlan-server.local -p 6600 load 1live] >[WMW:mpc -h tlan-server.local -p 6600 load wmw]" }  
% cat default.sitemap .... Frame label="Musik" { Switch item=Mpd_Kitchen_StartStop Slider item=Mpd_Kitchen_VolumeControl Switch item=Mpd_Kitchen_Channel_Selection mappings=[ "1live"="Eins Live", "wmw"="WMW"] } ....
% cat Musik.rules configurations/rules raspberrypi import org.openhab.core.library.types.* import org.openhab.core.persistence.* import org.openhab.model.script.actions.* import org.joda.time.DateTime import java.lang.Thread rule "Change channel" when Item Mpd_Kitchen_Channel_Selection received command then var channel = receivedCommand sendCommand( "Mpd_Kitchen_StartStop", "OFF") Thread::sleep(50) sendCommand( "Mpd_Kitchen_Channel", "CLEAR") Thread::sleep(50) switch channel { case '1live': sendCommand( "Mpd_Kitchen_Channel", "1LIVE") case 'wmw': sendCommand( "Mpd_Kitchen_Channel", "WMW") } Thread::sleep(50) sendCommand( "Mpd_Kitchen_StartStop", "ON") end

Some notes:

  • Since (i think) openHAB processes events asynchronously, i had to add some Thread::sleep between commands to MPD
  • MPD behaved kind of strange when just loading playlists. So to make sure i dont mix up my playlists, i first stop music playback, then clear the current playlist, load the new playlist, and turn playback back on. This happens fast enough so you do not notice it, but fixed a lot of weirdness when controlling it.

Conclusion

Right now, i only have one speaker connected. But adding more is just a matter of connecting, copying configuration files and starting services. Controlling it is easy enough, everybody on my house can handle it.

Everything works great!

Further steps

As mentioned before, to support streaming services like spotify etc. i am going to switch to mopidy, although i will have to check how different the configuration will be.

Since the server is available as a bluetooth device, you can connect your smartphone to it and have sound from your phone come out of your speaker in any room. I am still looking nito what it would take to have an easy interface to choose which input to send to which output.

Since the bluetooth speakers are just regular pulseaudio sinks, you can send other stuff to them. For example, i installed espeak, a text-to-speech software. With it, you can have the server tell you “Hey, you’ve got mail!’ whenever a new email arrives.

Or, going further down the home automation route: You could for example use the openHAB weather binding check for rain and if rain is expected, warn you to close the windows in rooms where windows are open.

If you used bluetooth speakers which also offer handsfree features and have a microphone, you could even built something like an always listening voice assistant.

Can MS Certificate Services be a Subordinate Enterprise CA beneath a Root CA created with OpenSSL

Yes this is possible, if you consider a few additional configuration entries for the openssl config file.


Suppose a scenario where you want to deploy a multi-tiered certificate authority, using open ssl on a non-networked (offline) device to store your top level Root Certificate Authority (a linux box perhaps).

The device would remain offline to mitigate the network attack vector to steal the private key of the top level Root CA.

Subsequently, a MS Enterprise Subordinate Certificate Authority would be certified in the certificate chain to certify downstream certificates.


The Microsoft Certificate Authority expects valid AIA and CDP locations in the root CA certificate.

These url locations should be entered in the openssl configuration file before creation of the root CA or certification of the MS subordinate enterprise CA.


Setting up a certificate authority with openssl is beyond the scope op this tutorial, but there is a very good tutorial on the subject hosted at https://jamielinux.com/docs/openssl-certificate-authority/index.html


This tutorial assumes that you have set up a Root certificate authority with openssl according above tutorial up until verifying the root certificate, keeping in mind the following additions to the openssl.cnf config file.


As per the tutorial, the openssl config file would reside on the following location: /root/ca/openssl.cnf


Under the [ v3_ca ] and the [ v3_intermediate_ca ] sections the following two lines need to be added:

(these are the valid AIA and CDP locations that the Microsoft CA expects to be present)


authorityInfoAccess = caIssuers;URI:http://root-ca.mydomain.local/root.pem

crlDistributionPoints = URI:http://root-ca.mydomain.local/root.crl


Note that these two files will need to be present on your MS webserver before completion of your certificate signing request from your MS Enterprise Subordinate CA, or else the completion of the certificate signing request will fail because the MS Enterprise Subordinate CA fails to verify the validity of the Root CA Certificate and the Subordinate certificate.

Windows 2012 R2 RDS – Configure RDS Certificates with own Enterprise CA

If you are planning to configure Windows 2012 R2 Remote Desktop Services in your environment and are planning to sign your own x509 certificates for it, then be advised that this is not as straight forward as creating a web server certificate.

You will need to create a new (duplicated from workstation) certificate template, and modify the template’s settings to incorporate the correct extensions when enrolling for a new certificate via this template.

Certificates in a Windows 2012 R2 Remote Desktop Services deployment, are typically implemented either via Powershell or the RDS deployment properties management console in Windows 2012 R2.

For simplification of this tutorial, we will be using the management console instead of Powershell.

As prerequisite for this tutorial, it is assumed that you already have an enterprise certificate authority, and remote desktop services deployement installed on your network.

Our first step will be the creation of a new certificate template, modified to enroll correct certificates for our RDS deployment.

Open your Certificate Authority management snap-in from your Enterprise CA on your network, right click certificate templates and select manage.

In the certificate templates console, scroll down until you find the ‘Workstation Authentication’ template.  Right click it and select Duplicate Template.

On the General tab of the new template, change the template display name to RDS Certificate Template and mark the checkbox to publish the certificate in Active Directory.

On the Request Handling tab, select ‘allow private key to be exported’.

On the Extensions tab, select Application Policies and select Edit.

Add Server Authentication to the list.

On the Subject Name tab, select ‘Supply in the request’.

Accept the resulting message.

Close the new template now by selecting ok, and close your Certificates Templates Console.

Go back to the certificate authority management snap-in and right click Certificate Templates, New, Certificate Template to issue:

Select the new RDS Certificate Template and click ok.

The new certificate template is now added to your Enterprise Certification Authority, and can now be used to enroll correct certificates for usage with Remote Desktop Services.

For proof of concept, we will enroll a certificate using this template on our Remote Desktop Broker Server.

Log in to your Remote Desktop Broker server, in my case, rdbroker01.

Open a management console by right clicking start, then run, type mmc and press enter.

Click File – Add/Remove Snap-in…

Select the Certificates snap-in and click add.

Select computer account and click next.

Select local computer and click finish.

Now we have the Certificates Store of the local computer open, we will be requesting a new certificate from within this console to our enterprise CA.

Under Certificates, Personal, right click the certificates folder and select all tasks, request new certificate.

Click next on the certificate enrollment window.

Make sure Active Directory Enrollment Policy is highlighted, and click next.

Select RDS Certificate Template, and click the link to configure additional information for enrollment.

On the certificate properties window, add a common name for the certificate, this may be your FQDN of your RDS broker server, subsequently, add alternative dns names for other roles that u might be hosting on the same server like your RDS web access, or if you are planning to use this certificate also on the other servers in your deployment, add the FQDN’s of the other servers as DNS entries.

On the General tab, fill in a descriptive name for the certificate that you are enrolling, after this, select ok to close the certificate properties window.

Now click the Enroll button to request your certificate to the Enterprise CA.

The Certificate Enrollment process should complete successfully, click finish to close the enrollment window.

In our Certificate Management Snap-in we can verify that our new certificate is enrolled and available to us.  If it is not displayed at first, then press F5 to refresh and make it visible.

We now need to export the certificate and the private key to import it again via our RDS management console.

Right click the certificate, select all tasks and click export.

Click next on the certificate export wizard.

Select yes, export the private key and click next.

Accept the default settings in this window and click next.

Set a password to protect your private key.

Set the filename to where you want to export the certificate.

Click finish to complete the certificate export.

Now that we have the exported certificate ready, we can finish the certificate installation on our Remote Desktop Management console.

Open Server Manager, and open Remote Desktop Services in the left pane, then click tasks, and edit deployment properties.

Go to certificates, highlight the role for which u want to deploy your certificate, and click select existing certificate.

Select, choose a different certificate, browse for your certificate, enter your certificate password, and select to allow the certificate to be added to the trusted root certification authorities store.  After that confirm with ok.

Click apply to apply the certificate.  After this action, the status will show OK and the level will be Trusted.

Howto Publish Offline Certificates and CRLs to Active Directory

Before publishing your offline Root CA cert, check the extensions on the Root CA server, esp on the CRL Distrisbution Point (CDP) extensions.


To publish the offline Root CA cert and CRL to AD, set the “Include in all CRLs” flag in the Root CA extension properties and use the certutil -dspublish command. Do note that file share CDP (FILE://) is not supported – only LDAP:// and HTTP://. I have tried and it’s not going to work. Similarly, you would need to specify where clients and servers can obtain the root cert (i.e. LDAP and/or HTTP) in the “Authority Information Access (AIA)” drop-down setting.


The “Include in all CRLs” flag specifies that the Active Directory publication location should be included in the CRL itself. It can be used by an offline CA to specify the LDAP URL for manually publishing CRLs on the Active Directory. The explicit configuration container must be explicitly set in the URL. Alternatively, the DSConfigDN value can be set in the registry by using “certutil –setreg ca\DSConfigDN CN=Configuration,DC=contoso,DC=com”. Note that the last two DC values (DC=contoso,DC=com for “contoso.com”) are to be replaced by your actual Domain Name.



Export out the Root CA cert and CRL files and import them into a domain member server.

To publish the Root Cert to the Root CA store on the Active Directory: certutil -f -dspublish RootCA.cer RootCA


To publish the CRL to Active Directory: certutil -f -dspublish Root-Test-CA.crl “LoneSrv1” “Root-Test-CA”. The last 2 parameters to specify the containers are optional but could be needed if the offline RootCA is non-Microsoft.

How to Publish a New Certificate Revocation List (CRL) from an Offline Root CA to Active Directory and a Web Server

It’s highly recommended when building your Microsoft PKI (Public Key Infrastructure) to have your Root CA offline after issuing the Enterprise Sub CA certificates. It’s recommended to minimize the access to the Offline Root CA as much as possible. The Root CA is not a domain joined machine and can be turned off without any problem.


One of the Key issue is the CRL generated from the Root CA, you need to set the CRL interval for a large value so that we don’t need to copy the CRL to an online location frequently and do not implement delta CRLs, because the publication of each delta CRL would require access to the offline root CA in order to copy the delta CRL to an online publication location. In order to change the CRL interval you need to:

  1. Turn on the Offline Root CA and login with Admin account
  2. Open the Certification Authority Console
  3. Right Click on the “Revoked Certificates” and click Properties.
  4. Set “CRL Publish interval” to a large value (Default is 26 Weeks) and  uncheck “Publish Delta CRL” check-box.

In order to Publish a new CRL from the offline Root CA to the Enterprise Sub CA you need to do the following:

  1. Publish a new CRL on the Root CA, this can be done by Right Click the “Revoked Certificates” – All Tasks – Publish                                                                                                                                                                                                                                                                                                                                                                                                                           
  2. Copy the CRL file from the Root CA located under %systemroot%\system32\certsrv\certenroll to the Sub CA Server
  3. Turn off the Root CA
  4. Copy the above file to the InetPub folder (HTTP Path) in the Sub CA server which is by default located under the C:\inetpub\wwwroot\Certdata
  5. Open an Admin Command Prompt and run the following command to publish it to the Active Directory (LDAP Path).                                                                                           certutil -f -dspublish ” C:\Inetpub\wwwroot\certdata\RootCA.crl

This process of renewing the CRL and publishing a new one is manually done since the Root CA is offline and thats why its better to make the CRL publish interval more than the default value so you won’t do it frequently. You may also want to set an automated reminder before the next renewal date.