Skip to content

Instantly share code, notes, and snippets.

@rohancme
Last active February 18, 2021 03:14
Show Gist options
  • Save rohancme/b6703a9d5c66e6fc9a7d to your computer and use it in GitHub Desktop.
Save rohancme/b6703a9d5c66e6fc9a7d to your computer and use it in GitHub Desktop.
Create an Azure VM using the Python SDK

Setting up a VM on Azure using the Python SDK

After over a day of going through their documentation, reading GitHub issues, going through the SDK unit tests and shudder the second page of google results, here's how:

Create a private key and cert (pem file):

openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout id_rsa -out myCert.pem

(id_rsa is your private key, myCert.pem is your CSR)

Generate the public key from the private key:

ssh-keygen -yf id_rsa > id_rsa.pub

Convert the cert to the .cer format:

openssl  x509 -outform der -in myCert.pem -out myCert.cer

Upload myCert.cer to the Azure portal

Settings -> Management Certificates -> Upload

Get your certificate's fingerprint:

openssl x509 -in myCert.pem -noout -fingerprint

Remove the ':'s from the fingerprint. Save this somewhere for later.

Now for the fun stuff..

Before you get into the python SDK you need another set of keys

Or at least a concatenation of 2 of the previous files (The private key and certifcate files). I'm just going to go with a separate set so it's easier to explain

Create a pem file with a private key and a certificate:

openssl req -x509 -nodes -days 365 -newkey rsa:1024 -keyout everything.pem -out everything.pem

Create the .cer file to upload:

openssl x509 -inform pem -in everything.pem -outform der -out different.cer

Upload the .cer file to the Azure management console

You know how..

Let's get our python on..

This is the high level procedure for creating a VM on the Azure portal:

  1. Create a Cloud Service
  2. Create a Storage Service
  3. Create a Container on the Storage Service
  4. Find an OS image that you like
  5. Create a VM that runs on the Cloud Service in 1, uses the OS image you found in 4 and create a Blob in the container you created in 3.

Totally straightforward huh?

Here's the code with comments. Comment/mail me if something isn't clear ( there's a 10% chance I might have more details)

# For brevity. Don't actually import *
from azure.servicemanagement import *
from azure.storage.blob import *


subscription_id = your_subscription_id
certificate_path = # The path to everything.pem we generated earlier


# Create a Service Management Service object. This is basically what we use to interface with the API:
sms = ServiceManagementService(subscription_id, certificate_path)

# Create a cloud service

# Because the name has to be unique in Their cloud :/
hosted_service_name = name_generator()
label = 'devOps test'
desc = 'Service for basic nginx server'
location = 'Central US'
sms.create_hosted_service(hosted_service_name, label, desc, location)


# Create a storage service

storage_acc_name = name_generator()
label = 'mystorageaccount'
location = 'Central US'
desc = 'My storage account description.'

sms.create_storage_account(storage_acc_name, desc, label,
                                    location=location)

# Retrieve the primary key of your storage account
# Maybe the secondary key works too?

storage_acc_key = None
acounts = sms.list_storage_accounts()
for account in acounts:
    if account.service_name == storage_acc_name:
        storageServiceObj = sms.get_storage_account_keys(account.service_name)
        storage_acc_key = storageServiceObj.storage_service_keys.primary


# Create a container
blob_service = BlobService(account_name=storage_acc_name,
                           account_key=storage_acc_key)

container_name = "vm-container"
blob_service.create_container(container_name)

# This is the url to the container we just created
container_url_template = "http://{}.blob.core.windows.net/{}"
container_url = container_url_template.format(storage_acc_name, container_name)

# This is the image I chose. 
# You can choose any of the images you get as a result of running sms.list_os_images()
image_name = "b39f27a8b8c64d52b05eac6a62ebad85__Ubuntu-14_04-LTS-amd64-server-20140414-en-us-30GB"

# This can be anything you want
blob_url = container_url + "/ubuntu.vhd"

# Create the Virtual Hardrive. It basically creates a harddrive at blob_url with the image specified
os_hd = OSVirtualHardDisk(image_name, blob_url)


# Upload the certificate we'd created earlier.
# Despite the fact that the file is in the pem format, specify the format as pfx (¯\_(ツ)_/¯).
cert_path = path to myCert.pem generated earlier

with open(cert_path, "rb") as bfile:
    cert_data = base64.b64encode(bfile.read()).decode() # decode to make sure this is a str and not a bstr
    cert_format = 'pfx'
    cert_password = ''
    cert_res = sms.add_service_certificate(service_name=hosted_service_name,
                        data=cert_data,
                        certificate_format=cert_format,
                        password=cert_password)
    # This is important - You need to wait for the status to be successful
    operation_result = sms.get_operation_status(cert_res.request_id)


# Create a LinuxConfigurationSet for configuring Linux VMs, there's an equivalent Windows Set
vm_name = name_generator()
linux_config = LinuxConfigurationSet(vm_name, username, password, True)

# Remember the fingerprint we'd retrieved earlier?

SERVICE_CERT_THUMBPRINT = fingerprint_retrieved_earlier

# Let's add the public keys to be uploaded
pk = PublicKey(SERVICE_CERT_THUMBPRINT,
               '/home/rohan/temp2/id_rsa.pub')

pair = KeyPair(SERVICE_CERT_THUMBPRINT, '/home/rohan/temp2/id_rsa.pub')

linux_config.ssh = SSH()

linux_config.ssh.key_pairs.key_pairs.append(pair)
linux_config.ssh.public_keys.public_keys.append(pk)


# Configure the VM to accept SSH connections on port 22
endpoint_config = ConfigurationSet()
endpoint_config.configuration_set_type = 'NetworkConfiguration'

ssh_endpoint = ConfigurationSetInputEndpoint(name='ssh', protocol='tcp', port='22', local_port='22', load_balanced_endpoint_set_name=None, enable_direct_server_return=False)
endpoint_config.input_endpoints.input_endpoints.append(ssh_endpoint)

# Finally create the VM:

sms.create_virtual_machine_deployment(service_name=hosted_service_name,
    deployment_name=hosted_service_name,
    deployment_slot='production',
    label=hosted_service_name,
    role_name=hosted_service_name,
    system_config=linux_config,
    network_config=endpoint_config,
    os_virtual_hard_disk=os_hd,
    role_size='Small')
@ZuluPro
Copy link

ZuluPro commented Apr 6, 2018

I loved this document, but it's obsolete due to ASM deprecation.
😢

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment