Securing RDS with certificates

In this post I’ll go through the process to implement certificates in a Microsoft RDS farm with Windows 2008 R2. It assumes that the RDS Gateway, Session Broker, Web Access and Session Host servers are installed and configured with remote apps already working.

The process describes how to generate the certificate request from a Windows 2008 R2 server, generate a Personal Information Exchange certificate so the same certificate can be used to sign RDP files on other servers that are part of the same rds farm; and configure the RDP connection and RemoteApp to use the certificate for server authentication and sign RDP files.

Note that during the process of generating the Personal Information Exchange the private key will be removed from the server where the server certificate was generated and stored with the .PFX file being password protected; this is done to protect the private key for the certificate.

Creating a Certificate Signing Request

Open Microsoft Management Console (mmc) and add the Certificates snap-in to configured for the local computer. From the Personal store under Certificates (Local Computer) Select All Tasks\Advanced Operations\ Create Custom Request …

This will bring the Certificate Enrolment window. Press Next once and it will prompt you to Select Certificate Enrolment Policy. Select Proceed without enrollement policy under Custom Request.On the Custom Request select the following options

  • Template: (No Template) Legacy key
  • Request format: PKCS #10

UPDATE: if you still have XP clients on your network then select CGN Key on the Template field, as per Rod comment below.

And press Next

For the Certificate Information press the arrow on the right hand-side of Details and then select Properties.

On the Certificate Properties window enter a Friendly name and Description.

On the Subject tab you will need to add the following properties, they are shown below with some values for example only. The Common Name is the FQDN of the RDS farm:

  • Common Name (CN) = rds.lab.local
  • Organizational Unit (OU) = IT
  • Organization (O) = The sheep network
  • Locality (L) = London
  • Country (C) = GB

You can change the values as required; make sure that the CN is equal to the name of the DNS name of the RDS farm. Note also that these are the minimum options required.

Open the Extensions tab and expand the Extended Key Usage (Application policies) and add Server Authentication and Code signing as selected options.

Select the Private Key tab and expand the Key options and select 2048 (or any other key size as you require) as the key size and tick the Make private key exportable, then press ok.

Select where to save the request and select also Base 64 as the file format

Unless the RDS farm name changes or the certificate expires the CSR is only required to be completed once. After the certificate request is signed by a Certification Authority (CA), Entrust or a private CA, the same certificate can be used on the other RDS servers; but it is required to be installed on the server were the request was made from first so it can be exported with its private key; and it is this certificate with the private key (pfx) that will be imported to the other RDS servers in the farm.

Import Certificate

Once the certificate has been generated by the CA  it will need to be imported into the server where the certificate request was generated.

Open mmc and add the Certificates snap-in to the local computer. From the Personal store under Certificates (Local Computer) select Import …

On the Certificate Import Wizard window type the location and name of the certificate or Browse to its location then press Next

Verify that the certificate store is Personal

Verify everything and press finish.

If the import was successful you will notice that on the store it will have a small key on its icon  ; if this isn’t the case then the server isn’t the server where the request was created and this certificate should be removed.

Export Personal Information Exchange (.PFX)

In order for a certificate be used for code-signing it needs to have a private key, this can be obtained from the server where the certificate was requested and imported and its identified by a small key on the certificate icon in the personal store .To start the export select the certificate then right-click select All Tasks\Export…

Note the presence of a key in the certificate icon

Press Next once and this will bring the Export Privte Key step of the wizard, and select Yes, export the private key then press Next

Select Personal Information Exchange – PKCS #12 (.PFX) as the Export File Format, tick the Include all certificate in the certification path if possible and Delete the private key if the export is successful.

Enter a strong password to protect the certificate with the private key. Remember that this certificate will be imported on the other RDS session host servers

Select or type the location to export the certificate to and save it as .pfx

Finally verify the settings, make sure the Export key is Yes and press Finish.

Keep the password and .PFX in a safe location as they are required to install the certificate on other machines.

Import Personal Information Exchange (.PFX)

To import the Personal Information Exchange certificate use the same procedure as described in Import certificate but select the .pfx file when prompted in the File to Import if using Browse change the file type to Personal Information Exchange.

You will be prompted for the certificate password. Do not check Mark this key as exportable. As this can be a security risk.

Refer to Import Certificate for further instructions.

Signing RDP files

On the RDS server open RemoteApp Manager, locate the Digital Signature Settings and press Change.

On the RemoteApp Deployment Settings window tick the Sign with a digital certificate in the Digital Signature tab, and then press Change.

A Windows Security window will pop-up with a list of valid certificates, select the certificate generated in the previously, press Ok

Back on the RemoteApp Deployment Settings window the information about the certificate being used will show under the Digital certificate details area. Press Apply and then Ok.

RemoteApp Manager main window will now display a green check and Signing as under Digital Signature Settings

RDP server authentication

This will change the certificate presented to the clients by the RDS server

On the RDS server open the Remote Desktop Session Host Configuration and select the connection to change the certificate, by default there is only one connection RDP-Tcp, and double-click on it.

On the General tab of the properties window press Select

A Windows Security window will pop-up with a list of valid certificates, select the certificate generated in the previously, press Ok

The properties window will now display the certificate being used. Press Apply and then Ok.

XenApp 6 server in wrong worker groups

Symptoms

A XenApp 6 server may ignore a work group after the renaming the worker group

Cause

This is caused because the server fails to update the registry key with the worker groups it belongs to.

Troubleshooting

To verify the list of worker groups a server belongs to check the registry key HKLM\SOFTWARE\Wow6432Node\Citrix\IMA\WorkerGroups It contains a list with all the worker groups that the server is member of.

Fix

To ensure that the server recognizes the new worker group name; remove the server from the worker group, check the registry used in troubleshooting and wait for the worker group to be removed from the list, note that at this time the old name will be showing in the registry; if the worker group isn’t removed from the registry you can remove it manually.

Once the worker group isn’t present in the registry, add the server back to the worker group list. Wait for a few seconds and check the same registry key again; the correct worker group should be displayed now.

Servers not present in EdgeSight

Symptoms

When a new server is commissioned from a template/image, after booting it might not be displayed in EdgeSight or a server that was being shown disappeared in replacement to the newly commissioned server.

Cause

The symptoms above can be caused if the EdgeSight agent as the wrong company information, in the registry, or the server is trying to use a guid that is being used by another server.

Troubleshooting

The two key aspects to verify is if the server has the wrong company information in the registry and/or the GUID is duplicated.

Wrong company information

Verify that the registry key Company has the correct value.

On 32bit systems check HKEY_LOCAL_MACHINE\SOFTWARE\Citrix\System Monitoring\Agent\EdgeSight, on 64bit systems check HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Citrix\System Monitoring\Agent\EdgeSight.

Duplicated GUID

If the registry key is correct, then verify that the server isn’t trying to use the GUID of another server. Open EdgeSight.ini located on “C:\Documents and Settings\All Users\Application Data\Citrix\System Monitoring\Data or C:\ProgramData\Citrix\System Monitoring\Data, depending if it’s Windows 2003 or Windows 2008.

Check that the SInstance used by the server isn’t assigned to another server. A way to find what are the GUIDs known to edgesight is to query its database

-- Lists servers with their department and guid
SELECT m.name, i.instid, d.name AS 'dept', i.[guid]
FROM [instance] AS i
LEFT JOIN machine AS m ON m.machid=i.machid
LEFT JOIN dept AS d ON d.deptid=i.deptid
ORDER BY d.name, m.name

This should give you and idea of what servers are in conflict, if it doesn’t the you need to check each server individually.

Workaround/Solution

The solution depends on the problem noticed while trouble shooting. It can be one or both.

To correct a wrong company value open the registry editor expand the keys used in troubleshooting and edit the Company key, changing it’s value to match your environment.

If the server is using a GUID that is already taken by another server; then connect to the server, stop the Citrix System Monitoring and Firebird Server – CSMInstance services, then using notepad open EdgeSight.ini located on “C:\Documents and Settings\All Users\Application Data\Citrix\System Monitoring\Data or C:\ProgramData\Citrix\System Monitoring\Data and remove the value of SInstance; close notepad saving the changes and start both Citrix System Monitoring and Firebird Server – CSMInstance services.

NOTE: It can take up to 24 hours before the server is displayed in EdgeSight.

Fixing the template

The following is a set of recommended changes to the golden template used to provision server with Citrix EdgeSight Agent installed. I’m also assuming that the server is running Windows 2008.

1) Verify that the value of company in the registry has the desired value.
2) Stop the Citrix System Monitoring service.
3) Stop the Firebird Server – CSMInstance service.
4) Delete RSDATR.FBD located at C:\ProgramData\Citrix\System Monitoring\Data\
5) Edit EdgeSight.ini located at C:\ProgramData\Citrix\System Monitoring\Data\ and remove the value of SInstance.
6) Shutdown the server and create the template.

NOTE: These steps should be done before shutting down the server and creating the template.

Advanced configuration with SpeedTouch 780

I needed to do some more advanced configurations with my SpeedTouch 780, enable SNMP, change DNS servers and  manage routes; which isn’t possible through the Web page, that’s when I started to think if there was another way to manage the device and there is one, a good old telnet session to the router with the default user of Administrator(with capital A), no password (just press enter) and you’re there. Now to help with your way around you might wan’t to look to the CLI reference manual (download from Thompson partners) and then start messing with it.

Enable SNMP

Shall we start with SNMP first then. There are four distinct different things that you will need to do before SNMP is available from the WAN interface. Set the system information, enable the SNMP_AGENT and assign it to an interface, finaly set the SNMP community name.
_{Administrator}=> :snmp config sysContact="ET phone home" sysName="don't call me names please" sysLocation="here can't you see me?"
_{Administrator}=> :service system modify name SNMP_AGENT state=enabled
_{Administrator}=> :service system ifadd name=SNMP_AGENT group=wan
_{Administrator}=> :snmp community add securityname=ROCommunity communityname=public_change_me
_{Administrator}=> :snmp community add securityname=RWCommunity communityname=private_change_me

Don’t forget to change the value of the communityname.

Change DNS servers

Change the DNS servers to other than the ones assigned from your ISP. This might sound a bit ridiculous but I prefer to use OpenDNS, to the ones provided by my ISP; their free package provide statistics, domain filtering among other features.

_{Administrator}=> :dns server route flush
_{Administrator}=> :dns server route add dns=208.67.222.222 metric=1 intf=RoutedEthoA
_{Administrator}=> :dns server route add dns=208.67.220.220 metric=1 intf=RoutedEthoA
_{Administrator}=> :dns server route list

Add routes

At last but not the least adding routes, in my case I have a ASA5505 sitting on the same network but I wan’t traffic for some networks (let’s say 192.168.55.0/24 and 10.0.11.0/24) to be sent to the ASA so it gets sent over a IPSEC VPN to a client network
_{Administrator}=> :ip rtadd dst=192.168.55.0/24 gateway=192.168.1.1
_{Administrator}=> :ip rtadd dst=10.0.11.0/24 gateway=192.168.1.1

Create a non-base policy template for SELinux

Those who use SELinux sometimes come across with application with a specific security context type, try to access a resource that belongs to another security context type, this will result in SELinux denying access to the resource even if permissions are set to 777 and you change the owner:group of the resource.

Lets have the following example, the vsftd daemon needs to read index.html that belongs to httpd daemon and is marked as httpd_sys_content_t security context.

root# ls -Z
-rw-r--r-- userA userA user_u:object_r:httpd_sys_content_t index.html

Doing if you look into the audit log you will find something similar to the following:

root# tail audit.log
type=AVC msg=audit(1297255596.902:49856): avc: denied { search } for pid=4830 comm="vsftpd" name="html" dev=dm-0 ino=13668059 scontext=user_u:system_r:ftpd_t:s0 tcontext=user_u:object_r:httpd_sys_content_t:s0 tclass=dir

At this stage you can use audit2allow to help you creating the vsftpd.te file

root# audit2allow > audit.log
#============= ftpd_t ==============
allow ftpd_t httpd_sys_content_t:dir search;

Below is a more complete vsftd.te file, to allow ftpd read, write etc on files and directories, system wide, that belong to the httpd_sys_content_t type.

module vsftpd 1.0;

require {
type ftpd_t;
type httpd_sys_content_t;
class dir { read write search getattr add_name remove_name create rmdir};
class file { lock read write getattr create append unlink rename};
}

#============= ftpd_t ==============
allow ftpd_t httpd_sys_content_t:dir { read write search getattr add_name remove_name create rmdir};
allow ftpd_t httpd_sys_content_t:file { lock read write getattr create append unlink rename};

now that we have our vsftpd.te file we need to transform it into a module(.mod) then into a policy packet(.pp) and finaly load it

root# checkmodule -M -m -o vsftpd.mod vsftpd.te
checkmodule: loading policy configuration from vsftpd.te
checkmodule: policy configuration loaded
checkmodule: writing binary representation (version 6) to vsftpd.mod
root# semodule_package -o vsftpd.pp -m vsftpd.mod
root# semodule -i vsftpd.pp

Or if you’re a lazy admin as myself you can use the follwing script, you just need to create the vsftpd.te file and run it passing the name of the module

#!/bin/bash
MODNAME= $1
if [ ! -f ${MODNAME}.te ];
then
        echo Couldn't find the ${MODNAME}.te, non-base policy module
        exit 1
fi
checkmodule -M -m -o ${MODNAME}.mod ${MODNAME}.te
if [ $? -gt 0 ];
then
        echo Error processing ${MODNAME}.te
        exit 1
fi
semodule_package -o ${MODNAME}.pp -m ${MODNAME}.mod
if [ $? -gt 0 ];
then
        echo Error creating policy module packet ${MODNAME}.pp
        exit 1
fi
semodule -i ${MODNAME}.pp
if [ $? -gt 0 ];
then
        echo Error installing policy module ${MODNAME}.pp
        exit 1
fi