How to build a VyOS 1.2.0 ISO Image

This started out as an experiment in running Linux containers on Windows, and it was coming along quite nicely until I got stuck trying to launch the build container. I decided to hold off on debugging it and switched up my game plan so I could put together this post for you all.

Build the Virtual Machine

Technically, you could use any physical or virtual Linux system as long as it supports the prerequisites. I chose to build a new Hyper-V virtual machine running CentOS 7 (1810) and scripted everything out.

You don’t need anything special; just a minimal installation. If you’re using Hyper-V, the following (or something very close to it) will get you started.

$VMName = "CentOS-01"

New-VM -Name $VMName -Path "D:\Hyper-V\Virtual Machines" -Generation 2 -MemoryStartupBytes 8GB -SwitchName "Contoso-LAN" -NewVHDPath "D:\Hyper-V\Virtual Hard Disks\$VMName-system.vhdx" -NewVHDSizeBytes 127GB
Add-VMDvdDrive -VMName $VMName -Path "E:\Disc Images\CentOS-7-x86_64-Minimal-1810.iso"
Set-VMFirmware -VMName $VMName -FirstBootDevice (Get-VMDvdDrive -VMName $VMName) -EnableSecureBoot Off
Set-VMMemory -VMName $VMName -DynamicMemoryEnabled $false
Start-VM -Name $VMName
vmconnect $env:COMPUTERNAME $VMName

Install Docker

Installing Docker couldn’t be much simpler. You’ll use curl to download and execute the installation script. Then you’ll set the Docker service to start on boot. Finally, you’ll start the Docker service.

curl -fsSL https://get.docker.com/ | sh
systemctl enable docker
systemctl start docker

Download the VyOS Build Repository

All you’re really doing here is pulling down the build scripts from the crux branch, but you’ll need to install the unzip package before unzipping the archive. Then you’ll change into the build directory so we can continue.

curl -O -L https://github.com/vyos/vyos-build/archive/crux.zip
yum install unzip
unzip crux.zip
cd vyos-build-crux

Build the VyOS Build Container

The Dockerfile is in the docker subfolder, so we use the following command to instruct Docker to build the image and tag it vyos-builder. Easy peasy… it just takes a while. Go have a coffee!

docker build -t vyos-builder docker

Run the VyOS Build Container

Now that we have the build container, let’s run it. The –rm parameter instructs Docker to remove the container when we exit. The -it parameter instructs Docker to run the container interactively. The –privileged parameter instructs Docker to run the container with (almost) all the capabilities of the host machine. The -v $(pwd):/vyos parameter instructs Docker to mount the current working directory on the host as /vyos within the container. The -w /vyos parameter instructs Docker to set /vyos as the current working directory within the container. The vyos-builder parameter just tells Docker to run the container image tagged with that value. And finally, the bash parameter instructs Docker to execute the bash command so you’ll have a shell to work with.

docker run --rm -it --privileged -v $(pwd):/vyos -w /vyos vyos-builder bash

Configure the Build

Now that the container is running, you should be at a prompt that looks something like this:

root@efa0ecf8a19d:/vyos#

You should already be in the right directory, so configuring the build is as easy as executing the following command.

./configure --architecture amd64 --build-by "your@email.tld" --build-type release --version 1.2.0

Build the ISO Image

Now, for the payoff! The following command will build the ISO image. This will also take a while, so top off that coffee and take another break.

make iso

You’re Done!

You should have a brand spanking new ISO image in the build directory.

[root@centos-01 vyos-build-crux]# ls -l build/vyos-1.2.0-amd64.iso build/live-image-amd64.hybrid.iso
-rw-r--r--. 1 root root 378535936 Feb 10 23:32 build/live-image-amd64.hybrid.iso
lrwxrwxrwx. 1 root root 27 Feb 10 23:32 build/vyos-1.2.0-amd64.iso -> live-image-amd64.hybrid.iso

Great work! Now fire it up and do your thing!

Azure Site-to-Site VPN with VyOS

I do a lot with my hybrid lab where some of my infrastructure resides on-premises and some resides in Azure. In today’s post, I’m going to describe how you can setup a site-to-site VPN between Azure and your local site using VyOS.

Azure Configuration

For the sake of demonstration, I’m going to set this all up from scratch using Azure PowerShell. You may need to make some adjustments, but I’ll try to call out any gotchas as we make our way through the configuration.

The first thing we’ll need to do is connect to Azure. When you run the following command, you’ll be asked to authenticate. Use an account that has the appropriate permissions.

Connect-AzAccount

Next, we’ll need a Resource Group. I’m going to call mine ContosoInfrastructure.

New-AzResourceGroup -Name ContosoInfrastructure -Location "South Central US"

Now, we need a Virtual Network and a couple of subnets. For our purposes here today, my on-premises network will live entirely within 172.16.0.0/16 and my Azure virtual network will be 172.17.0.0/16.

I’m going to create two subnets — a gateway subnet for the Virtual Network Gateway, and a corporate subnet for my Virtual Machines. You may need to make some adjustments if some forethought wasn’t put into your network design. Refer to Planning and design for VPN Gateway for more information.

$GatewaySubnet = New-AzVirtualNetworkSubnetConfig -Name GatewaySubnet -AddressPrefix "172.17.254.0/29"
$CorporateSubnet = New-AzVirtualNetworkSubnetConfig -Name CorporateSubnet -AddressPrefix "172.17.0.0/24"
$ContosoNetwork = New-AzVirtualNetwork -Name ContosoNetwork -ResourceGroupName ContosoInfrastructure -Location "South Central US" -AddressPrefix "172.17.0.0/16" -Subnet $GatewaySubnet,$CorporateSubnet

Now that the Virtual Network has been created, we need to grab the subnet details so we’ll have their identifiers.

$GatewaySubnet = Get-AzVirtualNetworkSubnetConfig -Name GatewaySubnet -VirtualNetwork $ContosoNetwork
$CorporateSubnet = Get-AzVirtualNetworkSubnetConfig -Name CorporateSubnet -VirtualNetwork $ContosoNetwork

The next part can take quite some time. It’s possible it could take 30 minutes or more, so be patient. We’re going to setup a public IP address and define the IP configuration for the Virtual Network Gateway. Then, we’re going to create the gateway itself.

Note: We’ll be using the Policy-based Virtual Network Gateway configuration.

$GatewayAddress = New-AzPublicIpAddress -Name GatewayAddress -ResourceGroupName ContosoInfrastructure -Location "South Central US" -AllocationMethod Dynamic
$GatewayIpConfiguration = New-AzVirtualNetworkGatewayIpConfig -Name GatewayIpConfiguration -SubnetId $GatewaySubnet.Id -PublicIpAddressId $GatewayAddress.Id
$VirtualGateway = New-AzVirtualNetworkGateway -Name VirtualGateway -ResourceGroupName ContosoInfrastructure -Location "South Central US" -IpConfiguration $GatewayIpConfiguration -GatewayType Vpn -VpnType PolicyBased -GatewaySku Basic

Next, we’ll setup a Local Network Gateway, which describes the on-premises part of the WAN, and create the gateway Virtual Network Gateway Connection that links the two networks together.

Note: Use your own public IP address and shared key.

$LocalGateway = New-AzLocalNetworkGateway -Name LocalGateway -ResourceGroupName ContosoInfrastructure -Location "South Central US" -GatewayIpAddress 64.xxx.xxx.19 -AddressPrefix "172.16.0.0/16"
$GatewayConnection = New-AzVirtualNetworkGatewayConnection -Name AzureToContoso -ResourceGroupName ContosoInfrastructure -Location "South Central US" -VirtualNetworkGateway1 $VirtualGateway -LocalNetworkGateway2 $LocalGateway -ConnectionType IPsec -SharedKey "acE1Bl7pxSUc6IvQ"

Now, let’s grab the public IP address that we’ll need in the next part.

Get-AzPublicIpAddress -Name GatewayAddress -ResourceGroupName ContosoInfrastructure | Select-Object -Property IpAddress

That should give you something like this:

IpAddress    
---------    
40.84.136.186

VyOS Configuration

I’m using version 1.1.8 and have gone through a straightforward basic configuration that sets the following:

  • Interface addresses
  • Default gateway
  • Blackhole routes
  • Basic source NAT
  • Basic firewall
configure

set interfaces ethernet eth0 address 64.xxx.xxx.19/29
set interfaces ethernet eth1 address 172.16.0.1/24

set protocols static route 0.0.0.0/0 next-hop 64.xxx.xxx.17
set protocols static route 10.0.0.0/8 blackhole distance 254
set protocols static route 172.16.0.0/12 blackhole distance 254
set protocols static route 192.168.0.0/16 blackhole distance 254

set nat source rule 100 outbound-interface eth0
set nat source rule 100 source address 172.16.0.0/16
set nat source rule 100 translation address masquerade

set firewall name WAN-to-LAN-v4 default-action drop
set firewall name WAN-to-LAN-v4 rule 10 action accept
set firewall name WAN-to-LAN-v4 rule 10 state established enable
set firewall name WAN-to-LAN-v4 rule 10 state related enable

set firewall name WAN-to-LAN-v4 rule 20 action accept
set firewall name WAN-to-LAN-v4 rule 20 icmp type-name echo-request
set firewall name WAN-to-LAN-v4 rule 20 protocol icmp
set firewall name WAN-to-LAN-v4 rule 20 state new enable

set firewall name WAN-to-LOCAL-v4 default-action drop
set firewall name WAN-to-LOCAL-v4 rule 10 action accept
set firewall name WAN-to-LOCAL-v4 rule 10 state established enable
set firewall name WAN-to-LOCAL-v4 rule 10 state related enable

set firewall name WAN-to-LOCAL-v4 rule 20 action accept
set firewall name WAN-to-LOCAL-v4 rule 20 icmp type-name echo-request
set firewall name WAN-to-LOCAL-v4 rule 20 protocol icmp
set firewall name WAN-to-LOCAL-v4 rule 20 state new enable

set interfaces ethernet eth0 firewall in name WAN-to-LAN-v4
set interfaces ethernet eth0 firewall local name WAN-to-LOCAL-v4

commit
save

Now, let’s setup the IKE and ESP groups.

set vpn ipsec ike-group ike-azure lifetime 28800
set vpn ipsec ike-group ike-azure proposal 1 dh-group 2
set vpn ipsec ike-group ike-azure proposal 1 encryption aes256
set vpn ipsec ike-group ike-azure proposal 1 hash sha1

set vpn ipsec esp-group esp-azure lifetime 3600
set vpn ipsec esp-group esp-azure pfs disable
set vpn ipsec esp-group esp-azure proposal 1 encryption aes256
set vpn ipsec esp-group esp-azure proposal 1 hash sha1

Next, we’ll setup the peer configuration using the pre-shared-secret we used when we setup the Virtual Network Gateway Connection earlier.

Note: Use your own public IP address and the peer address we captured earlier after setting up the Virtual Network Gateway in Azure.

set vpn ipsec ipsec-interfaces interface eth0
set vpn ipsec site-to-site peer 40.84.136.186 authentication mode pre-shared-secret
set vpn ipsec site-to-site peer 40.84.136.186 authentication pre-shared-secret acE1Bl7pxSUc6IvQ
set vpn ipsec site-to-site peer 40.84.136.186 connection-type respond
set vpn ipsec site-to-site peer 40.84.136.186 local-address 64.xxx.xxx.19
set vpn ipsec site-to-site peer 40.84.136.186 ike-group ike-azure

Here’s where we setup the tunnel itself and specify the networks on each side of the connection.

set vpn ipsec site-to-site peer 40.84.136.186 tunnel 0 esp-group esp-azure
set vpn ipsec site-to-site peer 40.84.136.186 tunnel 0 local prefix 172.16.0.0/16
set vpn ipsec site-to-site peer 40.84.136.186 tunnel 0 remote prefix 172.17.0.0/16

Before the tunnel will come up, we need to allow some traffic through the firewall. I’m only configuring UDP port 500; the rest of the traffic should be covered by the existing rules that allow established and related traffic.

You can be more verbose if you’d like. You’ll need UDP port 4500 if you’re doing NAT traversal, which isn’t covered in this post. You’ll also need ESP (Protocol 50).

Note: ESP is Protocol 50, not TCP or UDP port 50.

Lastly, I’m adding a rule to allow traffic from the remote networks.

set firewall name WAN-to-LOCAL-v4 rule 30 action accept
set firewall name WAN-to-LOCAL-v4 rule 30 protocol udp
set firewall name WAN-to-LOCAL-v4 rule 30 destination port 500
set firewall name WAN-to-LOCAL-v4 rule 30 state new enable

set firewall name WAN-to-LOCAL-v4 rule 40 action accept
set firewall name WAN-to-LOCAL-v4 rule 40 source address 172.17.0.0/16

Now, the last thing we need to do is exclude the VPN traffic from NAT.

set nat source rule 10 outbound-interface eth0
set nat source rule 10 source address 172.16.0.0/16
set nat source rule 10 destination address 172.17.0.0/16
set nat source rule 10 exclude

Don’t forget to commit and save!

commit
save

Testing

By now, your tunnel should be up. Let’s check from VyOS.

vyos@vyos:~$ show vpn ike sa
Peer ID / IP                            Local ID / IP
------------                            -------------
40.84.136.186                           64.xxx.xxx.19

    State  Encrypt  Hash    D-H Grp  NAT-T  A-Time  L-Time
    -----  -------  ----    -------  -----  ------  ------
    up     aes256   sha1    2        no     1247    28800


vyos@vyos:~$ show vpn ipsec sa
Peer ID / IP                            Local ID / IP
------------                            -------------
40.84.136.186                           64.xxx.xxx.19

    Tunnel  State  Bytes Out/In   Encrypt  Hash    NAT-T  A-Time  L-Time  Proto
    ------  -----  -------------  -------  ----    -----  ------  ------  -----
    0       up     0.0/32.0       aes256   sha1    no     295     3600    all

Looks good! Let’s check Azure now.

PS C:\> Get-AzVirtualNetworkGatewayConnection -Name AzureToContoso -ResourceGroupName ContosoInfrastructure | Select-Object -Property ConnectionStatus

ConnectionStatus
----------------
Connected       

Fantastic! Can we ping from on-premises to Azure?

C:\>ping 172.17.0.4

Pinging 172.17.0.4 with 32 bytes of data:
Reply from 172.17.0.4: bytes=32 time=45ms TTL=126
Reply from 172.17.0.4: bytes=32 time=46ms TTL=126
Reply from 172.17.0.4: bytes=32 time=46ms TTL=126
Reply from 172.17.0.4: bytes=32 time=45ms TTL=126

Ping statistics for 172.17.0.4:
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 45ms, Maximum = 46ms, Average = 45ms

And from Azure to on-premises?

C:\>ping 172.16.0.4

Pinging 172.16.0.4 with 32 bytes of data:
Reply from 172.16.0.4: bytes=32 time=44ms TTL=126
Reply from 172.16.0.4: bytes=32 time=46ms TTL=126
Reply from 172.16.0.4: bytes=32 time=43ms TTL=126
Reply from 172.16.0.4: bytes=32 time=44ms TTL=126

Ping statistics for 172.16.0.4:
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 43ms, Maximum = 46ms, Average = 44ms

Looks like we’re all set!

Conclusion

I hope this was helpful. There are a fair number of parts to consider here and firewall and NAT rules can definitely trip you up. But overall, once you get the hang of it, it’s really straightforward and you can get this up and running in less than an hour. And truth be told, most of that time is waiting for the Virtual Network Gateway to become available!

I love Azure. I love VyOS. And I love networking. If you have a cool idea for a post, let me know. I’m always looking for cool stuff to play with and share!

WSUS Maintenance Automation

May 2020 Update

It’s been a while since I published this post. There’s now a great guide that goes into more detail posted on the Microsoft support site.

The complete guide to Microsoft WSUS and Configuration Manager SUP maintenance

Original Post…

I have a three-for-one deal for you today! Setting up WSUS can be pretty easy if your needs are modest. But there are a few little things you might want to consider putting in place. Here are some simple tips that can help automate some of those tasks.

Decline Itanium Updates

First, does anyone really have Itanium servers they need to patch? Nope, didn’t think so. Run this PowerShell some time during the evening of the second Tuesday of each month and it will decline all those pesky updates for you.

Get-WsusUpdate -Approval AnyExceptDeclined | ? { $_.Update.Title -imatch "ia64|itanium" } | Deny-WsusUpdate

You can wrap it in a batch file pretty easily too, just watch the quotes.

@ECHO OFF
PowerShell.exe -Command "Get-WsusUpdate -Approval AnyExceptDeclined | ? { $_.Update.Title -imatch 'ia64|itanium' } | Deny-WsusUpdate"

Periodically Run the Server Cleanup Wizard

You mean you don’t go in every once in a while and run the Server Cleanup Wizard? You probably ought to, and with the following PowerShell, you won’t have to do it manually anymore! (Adjust the parameters to your liking, but I recommend including them all. Details can be found here.)

Get-WsusServer | Invoke-WsusServerCleanup -CleanupObsoleteComputers -CleanupObsoleteUpdates -CleanupUnneededContentFiles -CompressUpdates -DeclineExpiredUpdates -DeclineSupersededUpdates

You can put that in a batch file too.

@ECHO OFF
PowerShell.exe -Command "Get-WsusServer | Invoke-WsusServerCleanup -CleanupObsoleteComputers -CleanupObsoleteUpdates -CleanupUnneededContentFiles -CompressUpdates -DeclineExpiredUpdates -DeclineSupersededUpdates"

You’ll want to schedule this before the database maintenance I describe below. Once a week should be sufficient, but adjust for your environment.

Perform Database Maintenance

For this, you’ll need the sqlcmd utility, the SQL script, and have an understanding of the type of database backing WSUS.

If you’re using the Windows Internal Database on Windows Server 2012 or newer, go with this command:

sqlcmd -I -S np:\\.\pipe\MICROSOFT##WID\tsql\query -i D:\Scripts\WsusDatabaseMaintenance.sql

If you’re using the Windows Internal Database on Windows Server 2008 R2 or older, go with this one instead:

sqlcmd -I -S np:\\.\pipe\MSSQL$MICROSOFT##SSEE\sql\query -i D:\Scripts\WsusDatabaseMaintenance.sql

If you’re using SQL Server, talk to your SQL Server administrator for advice on how best to proceed. Hopefully you can take advantage of Windows Authentication. I wouldn’t recommend storing credentials as clear text in a batch file.

You might be asking why I didn’t use PowerShell. There is an Invoke-Sqlcmd command after all. It does not, however, have an option to enable quoted identifiers like the sqlcmd executable. Don’t fret. It’s an easy enough fix. Simply modify the first part of the SQL script by adding an additional SET statement like this:

USE SUSDB;
GO
SET NOCOUNT ON;
SET QUOTED_IDENTIFIER ON;

Now you can use the following PowerShell to accomplish the same thing as the sqlcmd commands above.

Invoke-Sqlcmd -ServerInstance "np:\\.\pipe\MICROSOFT##WID\tsql\query" -InputFile D:\Scripts\WsusDatabaseMaintenance.sql

And you can of course wrap that in a batch file as well. Mind the quotes on this one too.

@ECHO OFF
PowerShell.exe -Command "Invoke-Sqlcmd -ServerInstance 'np:\\.\pipe\MICROSOFT##WID\tsql\query' -InputFile D:\Scripts\WsusDatabaseMaintenance.sql"

Conclusion

There are other things we can do to help maintain and operate WSUS (like taking backups and performance tuning). Perhaps I’ll cover some of those topics in a future post. For now, I hope you found these tips useful!

 

Silently Install LAPS Management Tools

I was recently asked how to install the LAPS Management Tools from the command line. As I normally just double click the MSI and click through the wizard, I wasn’t sure how to accomplish this relatively simple task.

The default installation only installs GPO Client Side Extensions and can be completed using one of the following command lines:

msiexec.exe /i LAPS.x64.msi /quiet
msiexec.exe /i LAPS.x86.msi /quiet

If you want to install the full set of features on your management workstation, you can use one of the following command lines:

msiexec.exe /i LAPS.x64.msi ADDLOCAL=CSE,Management,Management.UI,Management.PS,Management.ADMX /quiet
msiexec.exe /i LAPS.x86.msi ADDLOCAL=CSE,Management,Management.UI,Management.PS,Management.ADMX /quiet

Or more simply one of the following command lines:

msiexec.exe /i LAPS.x64.msi ADDLOCAL=ALL /quiet
msiexec.exe /i LAPS.x86.msi ADDLOCAL=ALL /quiet

Hope this helps!

Unspecified Error When Copying A Large File Over a Virtual Machine Connection

From time to time I find I need to copy a large file to a Virtual Machine running on Hyper-V. Normally copying files is easy when using Enhanced Session Mode — a simple copy and paste is all you need… except when dealing with really large files. This is what you get when you try that:

2017-04-17 11_21_11

I ran into this error today when trying to copy a 5.47 GB ISO file, so I thought I’d share a quick tip on copying files using PowerShell Direct, a new feature of Hyper-V available in Windows 10 and Windows Server 2016.

$PSSession = New-PSSession -VMName SERVER-VM-01 -Credential (Get-Credential)
Copy-Item -ToSession $PSSession -Path C:\Local\Path\Image.iso -Destination C:\Remote\Path

That’s all there is to it!

Source: TechNet Blog Post by Ben Armstrong

New Home Lab

The Quest Begins

I trolled the homelab subreddit for a while, discussed options with friends and colleagues, and did a ton of research. I wanted something quiet, reasonably powerful, and expandable. While cost was a factor, it didn’t drive my decisions.

Many folks advocated purchasing older servers from eBay, where the Dell PowerEdge R710 is among the most popular options. It’s true there are really good deals out there for fairly powerful servers at very reasonable prices, but I chose a different route.

Unfortunately, commercial servers are generally pretty loud. I have to keep the server in my home office so I need something that won’t be distractingly loud. I also intend to migrate eight 3.5-inch drives and those older servers won’t accommodate that need.

Continue reading