Generally speaking, a DENY rule in Windows firewall will override any ALLOW.
As an example, if i want to do the right thing and DENY most PowerShell Remote (5985) in the environment i'd have a tough time allowing only my Privileged Access Workstations (PAWs) access without getting a little janky with IP ranges (which is brittle anyway).
This can be solved fairly easily with IPSec rules and you don't need to encrypt the traffic. Instead, we can use null encapsulation and tell IPSec just to do an extra layer of Kerberos v5 authentication to check that the packets are coming from the right user and the right computer.
In this example we will set up a few rules to achieve this goal using IPSec:
- We will DENY 5985 (PS Remote)
- We will make an exception to ALLOW 5985 if the user is both part of the "Enterprise Admins" group and if they are coming from one of my PAW machines (computers that are in the "PAW Computers") group.
Configuring the rules this way means that even if an enterprise administrator gets cheeky and tries to use their daily driver workstation to do some quick PS Remoting, they will be denied until they switch to the PAW because of the explicit deny on 5985 and the exception only matching the right machines and the right users.
Something like this:
The most straightforward way I've found to manage this is to use three group policies.
I can use security filtering on the group policy ACL's to get granular as needed:
- Policy to DENY 5985
- Policy to Allow 5985 if IPSEC is used
- Policy to tell the client device to use IPSEC for the destination port (5985)
I can attach those three in multiple places in the domain structure as needed.
- 'Domain Controllers' group should DENY all 5985
- 'PAW Computers' should still be allowed if 'Enterprise Admins' members are using them.
- Open GPMC.msc with a user who has permissions to attach policy to your target OU. For me, its the domain controllers OU so i'm going to use an enterprise admin account.
- Create two new policies in your target (no settings yet, just right click and choose "create a policy and attach it here").
- If you'd like to be careful (i do), adjust the policies so that just one machine is in scope for now. You can do that with the security filtering and delegation tabs. (You'll want to leave 'read' permission for 'authenticated users' but remove 'apply group policy'; then add 'apply group policy' for the target).
So far, you should have this:
Now we go ahead and block the desired port.
We can do this safely knowing that we are currently filtering to a single machine.
- Open the policy (right click, edit) and navigate to "Computer Configuration" > "Policies" > "Windows Settings" > "Security Settings" > "Windows Firewall with Advanced Security" > "Inbound Rules". Right click and choose "New Rule".
- On the "Rule Type" Menu, choose "Port" and click "Next"
- On the port and protocol i'll be choosing "TCP" and specifying port 5985.
- Action is "Block the connection"
- Profile is all three checkboxes.
- Name is anything, but i did "DENY 5985"
That's it for the DENY.
Group policy should update in 5 minutes on a domain controller but we can rush it with "gpudpate /force" if needed.
We can check if the rule is working using something like:
test-wsman -ComputerName dc1.chadduffey.com
In the example above, we can see that the firewall on dc1 is filtering PS Remote, but that dc2 is still OK because we are being careful and working with one machine to test the end to end solution first. (Even though the policy is linked to the entire domain controllers OU).
Next, we build the exception rule:
- Right click the Allow rule, and choose "edit" then navigate to "Computer Configuration" > "Policies" > "Windows Settings" > "Security Settings" > "Windows Firewall with Advanced Security" > "Inbound Rules". Right click and choose "New Rule".
- "Rule Type" is "Port"
- "Protocol and Port" is "TCP", 5985
- Action is "Allow the connection if it is secure" (IPSec). Click the "Customize" button.
- Click to "Allow the connection to use null encapsulation" and check "Override block rules". Click OK. Click Next.
- On the "Users" tab check "Only allow connections from these users", click "Add" and choose your user or group. I'm using "PAW Users".
- On the "Computers" tab, same deal, "Only allow connections from these computers", "add". Im using "Paw Computers"
- "Profile" can be left default, click next.
- "Name" can be anything, but i used "Allow 5985 via IPSEC"
We end up with something that looks like this:
We aren't done with this UI though. Don't close it just yet.
- Right click "Connection Security Rules" and choose "New Rule".
- Rule Type is "Custom"
- Endpoints is default "Any/Any"
- Requirements "Request authentication for inbound and outbound connections" (Remember, request is fine because the rule we created in the previous step ONLY allows 5985 if this IPSec part succeeds).
- Authentication Method is "Computer and User (Kerberos v5)
- Protocol and Ports: TCP, Endpoint 2 is 5985
- Profile, leave default and hit next.
- Name, i just called "IPSEC for 5985"
Now we have this connection security rule as well as the inbound rule:
All we have to do now is create a rule and apply it to the clients who need to IPSec.
For that, im just going to link the policy to the "Admin Endpoints" OU in my domain. I'm not going to worry about security filtering or anything fancy for this OU because i don't mind if they all know that they need to IPSec to the domain controllers for PS Remoting, even if only those in the right group will succeed.
I create an empty policy in the OU that contains my admin computers:
Right click, and choose edit:
- Jump down to: "Computer Configuration" > "Policies" > "Windows Settings" > "Security Settings" > "Windows Firewall with Advanced Security" > "Connection Security Rules". Right click and choose "New Rule".
- Choose "Custom" for "Rule Type"
- Click next for default on "Endpoints"
- Choose "Request Authentication for inbound and outbound connections".
- Choose "Computer and User (Kerberos v5)"
- "TCP" port 5985 for the "Protocols and Ports"
- Defaults and hit next on "Profile"
- For name, anything is fine but i used "Client IPSec for 5985"
That, should be it.
From the start button type "wf.msc"
Navigate to "Monitoring, Security Associations, Quick Mode". This will give us a visual of the IPSec connection.
(Wait here, or force gpupdate. Remember, the group policies wont apply for up to 90 minutes on the clients and servers and 5 minutes on domain controllers. If you want to rush, use gpupdate /force on any endpoint involved in this IPSec dance)
Once you are confident that policy has been applied to the machines, open Powershell and type:
test-wsman -ComputerName dc1.chadduffey.com
If things are working, you'll see:
- A successful connection.
- A quick mode IPSec association for port 5985
- A main mode IPSec association for kerberos authentication between the client and target.
IPSec Quick mode:
IPSec Main mode:
Once you are comfortable that the policy is correct, you can remove the security filtering on the group policy objects and expand to the full set of computers that you want to protect.
For me this means removing dc1.chadduffey.com in the security filtering, and replacing with "Domain Controllers"
We've locked down PS Remoting on port 5985. We left a gap for our admins but only when they are using their privileged access workstation, and their administrative account.