Pulumi: Create a virtual machine configured with Rancher on OpenStack - Part 1

The use case that we will study is part of a previously created OpenStack project. In this project, the security groups will be configured through Pulumi, an instance will be created that will be provisioned during its start with Rancher and it will be finished by assigning it a floating IP address.

Pulumi Package Resources for OpenStack
According to the documentation for the Pulumi package for OpenStack , there are a large number of modules for managing OpenStack resources with Pulumi, including block storage for Cinder, compute instances for Nova, identities for Keystone, images for Glance, networking for Neutron and shares for Manila.
Download OpenStack Project Credentials
From the OpenStack Horizon graphical interface we will follow these cases to download user credentials in the OpenStack project to use.
Select the OpenStack project in the user projects dropdown.
In the user menu dropdown select OpenStack RC File.
Load the downloaded credentials with source <credentials-filename>. Enter the password requested to access OpenStack.
For Windows users it is recommended to have WSL installed .
Creation and initial configuration of the project
From within an empty directory created for the project we will create the Pulumi project with the command pulumi new. If we do not indicate anything else, we will have to select the type of project by choosing both the platform and the language. This combination of project type (AWS, Azure, Google Cloud, Kubernetes, Linode, OpenStack) and language (Go, JavaScript, TypeScript, Python, C#) is known as a template. A faster way is to pass the template configuration parameter directly when creating the project
$ pulumi new openstack-typescript #1

  1. New project using the template with OpenStack as provider and TypeScript as language.

Next:

  • We will accept the name of the project, whose default value is that of the directory in which it is located.
  • We will complete the description with OpenStack VM Configuration.
  • We will accept the stack name ( dev).

A stack is a similar concept to the application deployment environment. We will be able to have different stacks for development, staging and production.
Once the project creation options have been accepted, the project's dependencies will be installed and a few moments later the project will be ready to run.
As a result we will have a project with the following structure:

├── .gitignore
├── index.ts #1
├── package.json #2
├── Pulumi.yaml #3
└── tsconfig.json

  1. File with the resources to deploy. Add an example
  2. Dependencies file. The OpenStack dependency appears as installed after creating the project with the templateopenstack-typescript
  3. Configuration of the name and description of the project and execution runtime

An instance as an example of an OpenStack resource
After creating the project with the OpenStack template, Pulumi includes a sample resource in the index.ts. It involves creating an OpenStack instance.

...
import * as os from "@pulumi/openstack"; //1

const instance = new os.compute.Instance("test", { //2
    flavorName: "s1-2",
    imageName: "Ubuntu 16.04",
});
...

  1. Importing the OpenStack resource bundle
  2. Create an instance

For the creation of the instance:

  • It is used osas an alias given to the OpenStack package.
  • The module computeand the resource are used Instance.
  • A name is assigned for the instance ( testin this case)
  • A JSON object is used to specify configuration parameters for the instance.

Configuring security rules
Security rules configure the OpenStack project's firewall. For the example at hand, Rancher initially requires TCP ports 80 and 443 to be open for HTTP traffic (HTTP and HTTPS). To implement it we can include these two security rules in the defaultproject group or create a specific security group for these two rules. Later, when configuring the instance, the security defaultgroup or the specific group created for the HTTP rules would be applied to it. In this example we chose to create a specific security group.
Creating specific security groups for security rule rule groups is more laborious than including the rules in the group default. However, having all the rules in the security group defaultcauses instances to have ports open unnecessarily, which can lead to a security issue.

Create a security group
Security groups are created with the SecGroupmodule resource networking. Simply provide a name for the security group and JSON for the options. In our case we will include the description of the security group.

const webSecGroup = new os.networking.SecGroup("web", {
    description: "Web security group"
})
This defines a security group assigned to a constant webSecGroup. Assigning the created resource to a constant or a variable allows you to manipulate it later. In our case, security rules will be added.
Add security rules
Security rules are added to security groups by creating a SecGroupRule module resource networking. It is about indicating a name for the security rules and a JSON for the options. In our case we will include a description, address, if it is IPv4 or IPv6, the open port (defined as a range), the protocol, the remote IP addresses to which access is given and the security group to which the rule is assigned. created
const web80 = new os.networking.SecGroupRule("web80", {
    description: "HTTP",
    direction: "ingress",
    ethertype: "IPv4",
    portRangeMax: 80,
    portRangeMin: 80,
    protocol: "tcp",
    remoteIpPrefix: '0.0.0.0/0',
    securityGroupId: webSecGroup.id, #1
});

const web443 = new os.networking.SecGroupRule("web443", {
    description: "HTTPS",
    direction: "ingress",
    ethertype: "IPv4",
    portRangeMax: 443,
    portRangeMin: 443,
    protocol: "tcp",
    remoteIpPrefix: '0.0.0.0/0',
    securityGroupId: webSecGroup.id, #2
});

  1. Assignment of the rule to a security group.
  2. Assignment of the rule to a security group.

Security Configuration Deployment
The complete security setup for an environment with Rancher and Kubernetes residing in the same OpenStack project includes a wide variety of security rules and groups. The official Rancher documentation specifies the list of ports to open for each component.
Doing an exhaustive definition of all security groups and rules in a project for production is beyond the scope of this tutorial. So here we will just include another security group as an example to see how to set up multiple security groups. We will take as an example the security configuration of database ports 2379 and 2380 etcd that Kubernetes uses for configuration storage.
Finally, the initial security configuration would be defined like this in the index.ts.

import * as os from "@pulumi/openstack";

const cidr = '192.168.129.0/24' //1

// Create security group //2
const etcdSecGroup = new os.networking.SecGroup("etcd", {
    description: "Kubernetes security group"
})

// Create security rule and assing to a security group //3
const etcd2379 = new os.networking.SecGroupRule("etcd2379", {
    description: "etcd",
    direction: "ingress",
    ethertype: "IPv4",
    portRangeMax: 2379,
    portRangeMin: 2379,
    protocol: "tcp",
    remoteIpPrefix: cidr, //4
    securityGroupId: etcdSecGroup.id, //5
});

// Create security rule and assing to a security group
const etcd2380 = new os.networking.SecGroupRule("etcd2380", {
    description: "etcd",
    direction: "ingress",
    ethertype: "IPv4",
    portRangeMax: 2380,
    portRangeMin: 2380,
    protocol: "tcp",
    remoteIpPrefix: cidr,
    securityGroupId: etcdSecGroup.id,
});

// Create web security group
const webSecGroup = new os.networking.SecGroup("web", {
    description: "Web security group"
})

// Create security rule and assing to a security group
const web80 = new os.networking.SecGroupRule("web80", {
    description: "HTTP",
    direction: "ingress",
    ethertype: "IPv4",
    portRangeMax: 80,
    portRangeMin: 80,
    protocol: "tcp",
    remoteIpPrefix: '0.0.0.0/0',
    securityGroupId: webSecGroup.id,
});

// Create security rule and assing to a security group
const web443 = new os.networking.SecGroupRule("web443", {
    description: "HTTPS",
    direction: "ingress",
    ethertype: "IPv4",
    portRangeMax: 443,
    portRangeMin: 443,
    protocol: "tcp",
    remoteIpPrefix: '0.0.0.0/0',
    securityGroupId: webSecGroup.id,
});

  1. CIDR to allow remote access to instances to which security rules apply for that CIDR
  2. Create a security group
  3. Create a rule for a security group
  4. Application of CIDR to security rule
  5. Assigning the security rule to a security group

The changes would be displayed with pulumi up and selecting the option yes. The option details shows the details of each of the resources to be created, modified or deleted in the infrastructure.
If the error appears when performing the deployment, One of 'auth_url' or 'cloud' must be specified it is because the OpenStack credentials have not been loaded. See the Downloading the OpenStack project credentials section .
The following figure shows the effect of the deployment with the two security groups created.

The following figure illustrates the group security rules web. For that group, access to these ports is allowed from any Internet address.

No comments

Powered by Blogger.