First off, I'm really glad you're reading through this guide. I put a lot of effort into it. Because of this, there's a lot of information packed within this Gist guide. None of it is difficult, but please read through it carefully so you have the best outcome.
There are some concepts you may already be familiar with, but some you may not be as familiar with as well (i.e. you may not be aware of Palo Alto's Bootstrapper process, even if you've been a firewall admin for a long time).
As a security-architect-turned-platform-architect for a very large service provider for much of my career, I want the most perfect experience possible (combining both security + safe GitOps). There are no shortcuts here. So if you see something you have questions about, please feel free to put your questions below! I will be happy to assist in any way that I can. The goal is to make sure your PoC is interesting and successful.
This Gist assumes that you are coming from the original GitHub Gist located HERE. The goal for this Gist is to get a Palo Alto VM running on OpenShift Virtualization. These steps assumed you have performed the following steps first:
- You have set up OpenShift Storage, or some other CSI-based storage option that is supported from OpenShift Virtualization.
- You have SR-IOV supported device NICs available and configured within your OpenShift cluster (more on this below).
- A private registry is required for PanOS/Panorama images (QCOW2 images stored in an OCI-compliant container image format). I'll provide detailed instructions on how to use a free, private registry on Red Hat's Quay.io ([down below](Build PanOS and Panorama Boot Images)), however you can use your own private registry if you'd like.
The goal of this document is to dog-food your newly created OpenShift Virtualization environment for engineering and management. Start a new RHEL or Fedora virtual machine within OpenShift Virtualization.
- Where you see
(Fedora)
at the beginning of a Step number below, you will use your Fedora or RHEL virtual machine in OCPV. - Where you see a
(Workstation)
at the beginning of a Step number below, you will use your own PC or workstation. Please note that I am using a MacBook Pro for my Workstation, so some of my commands may vary just slightly from your own (although I tried to take some of this into account within my instructions below).
Some of the instructions below are taking advantage of Palo Alto's Bootstrap Package method, using an older (yet still working) PanOS-Bootstrapper Utility on GitHub. This project will create a companion ISO that is attached while the VM first comes online, and it will do the following:
- Automatically set the management IP Address
- License the Firewall
- Check into Panorama and pull down rules and configuration
This is all done automatically, and completely touchless from the administrator. All you have to do is follow these instructions, and begin the demonstration below.
With these things now out of the way (and potentially clarified as far as goals are concerned), let's begin!
- (Fedora) Update the system and install Git and ansible
sudo yum update -yy && sudo yum install -yy git podman tree
-
(Fedora) Set the global user/email for Git
git config --global user.name "Brandon B. Jozsa" git config --global user.email "[email protected]"
-
(Fedora) Create the following directories that we will use throughout this project
mkdir -p {~/development/dockerfiles/panorama/,~/development/dockerfiles/panos/,~/development/panos-images/,~/Downloads/,~/.kube/}
-
(Fedora) Download the follow Dockerfiles for Panorama and PanOS:
curl -L https://gist.githubusercontent.com/v1k0d3n/ffbba6fd2908ecb1b30b87780ff6d8b1/raw/9938d64e682bb9e84948d906c7d6704e21a63dc7/Dockerfile-panos -o ~/development/dockerfiles/panos/Dockerfile curl -L https://gist.githubusercontent.com/v1k0d3n/ffbba6fd2908ecb1b30b87780ff6d8b1/raw/9938d64e682bb9e84948d906c7d6704e21a63dc7/Dockerfile-panorama -o ~/development/dockerfiles/panorama/Dockerfile
-
(Fedora) Make sure that the Fedora host has the
oc
andvirtctl
Linux binaries. First make sure that your Fedora environment has a~/.kube/
directory and then copy thekubeconfig
into that directory, but as namedconfig
. If this is confusing, please review this documentation.- Details: Copy the downloaded
kubeconfig
from your cluster and name it~/.kube/config
on the Fedora host.
- Details: Copy the downloaded
-
(Fedora) Get the latest
oc
Linux binary for OpenShift:curl -L https://mirror.openshift.com/pub/openshift-v4/clients/ocp/stable-4.16/openshift-client-linux-4.16.10.tar.gz -o ~/Downloads/openshift-client-linux-4.16.10.tar.gz
-
(Workstation) Download the
virtctl
binary for Linux by going to the OpenShift console and clicking on the top right-hand corner on the?
(question mark), and clicking on Command Line Tools. Download the one that says Download virtctl for Linux for x86_64. -
(Workstation) Set a variable on your workstation that will make life easier later when we copy files from your workstation to your Fedora VM. You want to put YOUR FEDORA IP ADDRESS as the variable below:
primary_ip="PUT_YOUR_IP_HERE_AND_KEEP_QUOTES"
-
(Workstation > Fedora) Use
scp
or some other utility to thevirtctl.tar.gz
tarball to the Fedora virtual machine.STOP: Change the information below to match your own environment. This includes the
$USER
and the variable you set earlier ($primary_ip
), because these will be different for each environment.scp ~/Downloads/virtctl.tar.gz fedora@$primary_ip:/home/fedora/Downloads/virtctl.tar.gz
-
(Fedora) Back on the Fedora virtual machine, unpack both of these packages and copy the executables to
/usr/local/bin/
# Go to the ~/Downloads folder, and untar the binaries for oc, kubectl, and virtctl: cd ~/Downloads/ tar zxvf openshift-client-linux-4.16.10.tar.gz tar zxvf virtctl.tar.gz # Copy the binaries to /usr/local/bin/: sudo cp virtctl /usr/local/bin/ sudo cp oc /usr/local/bin/ sudo cp kubectl /usr/local/bin/
-
(Fedora) Check that you can communicate with OpenShift:
[fedora@fedora-panos-devel-3 Downloads]$ oc get nodes NAME STATUS ROLES AGE VERSION roderika Ready control-plane,master,worker 5d23h v1.29.7+4510e9c
-
(Fedora) Run the following podman command:
sudo podman run -d --network=host paloaltonetworks/panos-bootstrapper:latest
-
(Fedora) Get the IP address of your server, and then create following variable with that IP where the
PUT_YOUR_IP_HERE_AND_KEEP_QUOTES
notation is below:IMPORTANT: Get the IP address of your Fedora VM first with the following command:
ip addr
When you find the IP address you need, enter it as a variable (
primary_ip
).primary_ip="PUT_YOUR_IP_HERE_AND_KEEP_QUOTES"
-
(Fedora) Change into the following directory called
panos-images
:cd ~/development/panos-images/
-
(Fedora) Look at the following sample. Configure your firewall variables to match your own deployment/environment:
IMPORTANT: The
auth_code
will be the authorization code for your Palo Alto VM-series firewall license. You may need to check your email for this code.# Set variables to be used in the curl command below: hostname="panos-01" management_ip="192.168.3.105/24" management_gateway="192.168.3.1" dns_servers='["192.168.3.5", "192.168.3.5"]' auth_code="REMOVED" panorama_ip="192.168.3.95" panorama_port="3978" timezone="UTC" # Use the following code to generate an ISO that will be used to configure your firewall (ZTP): curl -X POST http://$primary_ip:5000/bootstrap_kvm \ -H "Content-Type: application/json" \ -d '{ "hostname": "'"$hostname"'", "archive_type": "iso", "management_ip": "'"$management_ip"'", "management_gateway": "'"$management_gateway"'", "dns_servers": '"$dns_servers"', "auth_code": "'"$auth_code"'", "panorama_ip": "'"$panorama_ip"'", "panorama_port": "'"$panorama_port"'", "timezone": "'"$timezone"'" }' --output /home/fedora/development/panos-images/panos-bootstrap-$hostname.iso
-
(Fedora) Now go back to your CLI that is communicating with OpenShift Virtualization, and type the following commands. BE SURE to change with your own variables for
namespace
:hostname="panos-01" namespace="jinkit-vms" # Be sure to use virtctl to create the ISO/pvc first: virtctl image-upload pvc panos-bootstrap-$hostname-config-iso \ --size 1Gi \ --image-path=/home/fedora/development/panos-images/panos-bootstrap-$hostname.iso \ --namespace=$namespace \ --force-bind \ --volume-mode=block \ --insecure
-
(Workstation) Download the PanOS and Panorama update from the Palo Alto website (11.2.0)
For this you will need to go to the following navigation path:
- PAN-OS: Updates > Software Updates > PAN-OS for VM-Series KVM Base Images and select PA-VM-KVM-11.2.0.qcow2.
- Panorama: Updates > Software Updates > Panorama Base Images and select Panorama-KVM-11.2.0.qcow2.
- PAN-OS: Updates > Software Updates > PAN-OS for VM-Series KVM Base Images and select PA-VM-KVM-11.2.0.qcow2.
-
(Workstation > Fedora) SCP The files from your local machine to the Fedora Development VM (these are example directories, so be sure to change for your environment):
Important: Be sure to use your own Workstation
PATH
and$USER
. The syntax is for example only, and will not match your environment exactly as shown below:scp ~/Downloads/PA-VM-KVM-11.2.0.qcow2 [email protected]:/home/fedora/development/dockerfiles/panos/PA-VM-KVM-11.2.0.qcow2 scp ~/Downloads/Panorama-KVM-11.2.0.qcow2 [email protected]:/home/fedora/development/dockerfiles/panorama/Panorama-KVM-11.2.0.qcow2
-
Go to your registry and get your user credentials. I will show you how to do this for Quay.
- If you don't already have an account, create one.
- Then when you are logged in, go to the very top right-hand corner and click on your username.
- Click on Account Settings and on the left-hand menu click on the Gear Icon.
- This pulls up a section called *Docker CLI Password.
- For the CLI Password section click on Generate Encrypted Password.
- It will ask you to verify your credentials. Enter them now.
- This will now have an open window that says Credentials for USER.
- On the left-hand side of this window, click on the Podman Login option.
- Copy the
podman login -u='USER' -p=
string. - Paste this string into your Fedora CLI to authenticate Podman to your custom personal registry.
-
(Fedora) Run the following podman commands to build the correct containers. MAKE SURE to replace
USERNAME
with your actual username for Quay.Important: Set the following variable for your QUAY USERNAME.
quay_username=bjozsa-redhat
Important: Be sure to use your own Workstation
PATH
and$quay_username
are set correctly. The syntax is for example only, and will likely not match your environment exactly as shown below:cd /home/fedora/development/dockerfiles/panos/ podman build -t quay.io/$quay_username/pa-vm:11.2.0 . cd /home/fedora/development/dockerfiles/panorama/ podman build -t quay.io/$quay_username/panorama:11.2.0 .
-
(Fedora) Now push these images to your Quay registry. Like the previous command, MAKE SURE to replace
USERNAME
with your actual username for Quay.Important: Be sure to use your own Workstation
PATH
and$USER
. The syntax is for example only, and will not match your environment exactly as shown below:podman push quay.io/$quay_username/pa-vm:11.2.0 podman push quay.io/$quay_username/panorama:11.2.0
-
(Fedora) Now create a secret for your private registry (where you pushed the images). By default, Quay will make your container images private. DO NOT EXPOSE PALO ALTO IMAGES WITHOUT AUTHORIZATION! In order to keep these images private but allow the VM to download what it needs, we need to create a secret for your registry.
# Change the namespace to your own namespace: secret_name="quay-creds-registry-panos" namespace="jinkit-vms" # Do not change below this point: read -p "Enter Username: " username read -sp "Enter Password or Token: " password echo # This ensures a newline after password input encoded_username=$(printf "%s" "$username" | base64 -w 0) encoded_password=$(printf "%s" "$password" | base64 -w 0) oc apply -f - <<EOF apiVersion: v1 kind: Secret metadata: labels: app: containerized-data-importer name: $secret_name namespace: $namespace type: Opaque data: accessKeyId: "$encoded_username" secretKey: "$encoded_password" EOF
-
(Fedora) Make sure that you have the SR-IOV operator installed, and that you have configured two
SRIOVNetworks
. Think of one network as the "trusted" network, and one network as the "untrusted" network. I will show you a couple of examples down below.Trusted:
oc apply -f - <<EOF apiVersion: sriovnetwork.openshift.io/v1 kind: SriovNetworkNodePolicy metadata: name: policy-sriov-ens6f1np1-0031 namespace: openshift-sriov-network-operator spec: deviceType: vfio-pci isRdma: false nicSelector: deviceID: 101d pfNames: - ens6f1np1#0-31 vendor: 15b3 nodeSelector: feature.node.kubernetes.io/network-sriov.capable: "true" numVfs: 64 priority: 99 resourceName: ens6f1np1_0031 --- apiVersion: sriovnetwork.openshift.io/v1 kind: SriovNetwork metadata: annotations: operator.sriovnetwork.openshift.io/last-network-namespace: jinkit-vms name: ens6f1np1-vlan3-d namespace: openshift-sriov-network-operator spec: ipam: |- { "ipam": { "type": "dhcp" } } logLevel: info networkNamespace: jinkit-vms resourceName: ens6f1np1_0031 vlan: 3 EOF
Untrusted:
oc apply -f - <<EOF apiVersion: sriovnetwork.openshift.io/v1 kind: SriovNetworkNodePolicy metadata: name: policy-sriov-ens6f1np1-3263 namespace: openshift-sriov-network-operator spec: deviceType: vfio-pci isRdma: false nicSelector: deviceID: 101d pfNames: - ens6f1np1#32-63 vendor: 15b3 nodeSelector: feature.node.kubernetes.io/network-sriov.capable: "true" numVfs: 64 priority: 99 resourceName: ens6f1np1_3263 --- apiVersion: sriovnetwork.openshift.io/v1 kind: SriovNetwork metadata: annotations: operator.sriovnetwork.openshift.io/last-network-namespace: jinkit-vms name: ens6f1np1-vlan90-d namespace: openshift-sriov-network-operator spec: ipam: |- { "ipam": { "type": "dhcp" } } logLevel: info networkNamespace: jinkit-vms resourceName: ens6f1np1_3263 vlan: 90 EOF
-
(Fedora) Before creating the PanOS VM-Series Firewall, first create the Panorama management instance (named
panorama-01
). Use the following deployment below simply as an example. Complete the variables according to your own environment, and the deployment should "just work" as-is:# Variables namespace=jinkit-vms instance_name=panorama-01 secret_name="quay-creds-registry-panos" nad_mgmt01=ens6f1np1-vlan3-d nad_mgmt02=ens6f1np1-vlan3-d mac_mgmt01="02:9b:48:00:18:51" mac_mgmt02="02:9b:48:00:18:52" registry_image="docker://quay.io/bjozsa-redhat/panorama:11.2.0" disk_size="150Gi" core_count="16" memory_count="36G" # Virtual Machine Deployment oc apply -f - <<EOF --- apiVersion: kubevirt.io/v1 kind: VirtualMachine metadata: name: $instance_name namespace: $namespace spec: dataVolumeTemplates: - apiVersion: cdi.kubevirt.io/v1beta1 kind: DataVolume metadata: creationTimestamp: null name: $instance_name spec: source: registry: secretRef: $secret_name url: "$registry_image" storage: resources: requests: storage: $disk_size running: false template: metadata: labels: kubevirt.io/size: small kubevirt.io/domain: $instance_name spec: domain: cpu: cores: $core_count devices: disks: - name: rootdisk disk: bus: virtio interfaces: - name: $instance_name-port1 macAddress: $mac_mgmt01 model: virtio sriov: {} - name: $instance_name-port2 macAddress: $mac_mgmt02 model: virtio sriov: {} resources: requests: memory: $memory_count networks: - name: $instance_name-port1 multus: networkName: $nad_mgmt01 - name: $instance_name-port2 multus: networkName: $nad_mgmt02 volumes: - name: rootdisk dataVolume: name: $instance_name EOF
-
(OpenShift Console) In the OpenShift console, navigate to the VM you've just created (check the variables above, but if left default the name of the vm should be called
panorama-01
.- Click on the Configuration tab.
- Next, click on the Storage tab.
- Click on the blue box that says Add disk
- In the new window (Add disk), use the Name
storage-disk-01
- Source should be
Empty disk (blank)
- PersistentVolumeClaim size should be
75 GiB
or higher - Type should be set to
Disk
- Interface should be set to
VirtIO
- StorageClass should be set to
lvms-vg1-immediate
- Make sure the option Apply optimized StorageProfile settings is
checked
- Click the blue Save button when completed
-
Start the VM (you will notice that the VM was created earlier, but not started per the
running: false
option). -
Complete the setup of Panorama as you would normally.
-
(Fedora) Now you can deploy the first PanOS VM-Series Firewall (named
panos-01
). Use the following deployment below simply as an example. Complete the variables according to your own environment, and the deployment should "just work" as-is - just like the Panorama instance above:# Variables namespace=jinkit-vms instance_name=panos-01 secret_name="quay-creds-registry-panos" nad_mgmt01=ens6f1np1-vlan3-d nad_mgmt02=ens6f1np1-vlan3-d nad_trusted=ens6f1np1-vlan60-d nad_untrusted=ens6f1np1-vlan90-d mac_mgmt01="02:9b:48:00:18:11" mac_mgmt02="02:9b:48:00:18:12" mac_trusted="02:9b:48:00:18:13" mac_untrusted="02:9b:48:00:18:14" registry_image="docker://quay.io/bjozsa-redhat/pa-vm:11.2.0" disk_size="80Gi" core_count="8" memory_count="16384M" # Virtual Machine Deployment oc apply -f - <<EOF --- apiVersion: kubevirt.io/v1 kind: VirtualMachine metadata: name: $instance_name namespace: $namespace spec: dataVolumeTemplates: - apiVersion: cdi.kubevirt.io/v1beta1 kind: DataVolume metadata: creationTimestamp: null name: $instance_name spec: source: registry: secretRef: $secret_name url: "$registry_image" storage: resources: requests: storage: $disk_size running: true template: metadata: labels: kubevirt.io/size: small kubevirt.io/domain: $instance_name spec: domain: cpu: cores: $core_count devices: disks: - name: rootdisk disk: bus: virtio - name: $instance_name-config-iso cdrom: bus: sata interfaces: - name: $instance_name-port1 macAddress: $mac_mgmt01 model: virtio sriov: {} - name: $instance_name-port2 macAddress: $mac_mgmt02 model: virtio sriov: {} - name: $instance_name-port3 macAddress: $mac_trusted model: virtio sriov: {} - name: $instance_name-port4 macAddress: $mac_untrusted model: virtio sriov: {} resources: requests: memory: $memory_count networks: - name: $instance_name-port1 multus: networkName: $nad_mgmt01 - name: $instance_name-port2 multus: networkName: $nad_mgmt02 - name: $instance_name-port3 multus: networkName: $nad_trusted - name: $instance_name-port4 multus: networkName: $nad_untrusted volumes: - name: rootdisk dataVolume: name: $instance_name - name: $instance_name-config-iso persistentVolumeClaim: claimName: panos-bootstrap-$instance_name-config-iso EOF