Sunday, June 3, 2018

Azure from an AWS user

I've been getting my hands dirty in Azure recently. Until about a month ago all of my cloud experience has been in AWS, but we're sitting on a mountain of unused Azure credits and I think it makes good sense to chip away at these.

1. Service principals are a lot easier to grok and manage than IAM roles

I found it took a long time for me to properly grok IAM roles and use them effectively. Service principals in Azure though seemed to click right away.

2. Blob service not allowing default pages or SSL on custom domains is a huge drag

I really like using S3 for static website hosting. It's simple, easy, and I don't need to manage infrastructure. So, I was hoping that blob storage would fill a similar niche. But it doesn't yet.

Some guides out there made the recommendation to use CDN to make up for the shortfalls in blob storage's functionality, but after playing around with it I wasn't happy. It sort of worked, but the four hour plus turnaround time in configuration changes made iteration hard. I should have realized I was using the wrong tool for the job earlier.

That said, "premium CDN" not offering programmatic expiration/purging of assets is kinda silly

3. Resource groups are awesome!

I like the concept, I like the implementation. It's like the accounting you get with CloudFormation stacks but without having to use CloudFormation.

4. Azure File storage is light years better than EFS

Not like it's a high hurdle to clear but I've been noticing much better performance out of Azure File than from EFS. Easier to get going, no need to manage endpoints, etc.

5. Azure storage has terrible security defaults

Unsecure-by-default may be reasonable if you're using blob storage for static website hosting, but if you're using it for build artifacts then it's terrible.

6. Terraform support is less complete for Azure than AWS

There's things that I find missing in Terraform's support that I keep expecting to be there. For example, a data source representing a load balancer. It doesn't appear to have one, so one of my scripts has an IP hardcoded to the load balancer's IP. 

7. VM image management isn't as slick as AMIs

This may be a tooling thing (ie: Packer/Terraform/Spinnaker) more than an Azure thing; I was really enjoying being able to bake base images in AWS that included all the things I needed. But I can't, for example, seem to bake my own base image and use it in Spinnaker or Packer for building other images.

Using Kubernetes has mostly made this unnecessary though.

8. I miss using accounts for separation of concerns

I like that it's really easy in AWS to create a new account for some set of features. Like, a production account, a staging account, an account for hosting raw data, an account for hosting infrastructure, and yet another one for hosting, well, user accounts.

Azure isn't really architected to make that a possibility.

9. Lack of customizability for Azure Active Directory Domain Services is a drag

I was using the AWS Simple Directory for simple user account management and it was great. One of the things I liked was that I had enough control over directory content to be able to stuff user SSH keys into attributes. This worked really well, it was really easy to manage distribution of keys.

But with AADDS I can't create custom attributes, nor am I able to retrieve content out of what few attributes I can edit. Boo.

In general, some things seem to work better on Azure than AWS, and some things work better on AWS than Azure. Even though the UI of the Azure portal feels more consistent than the AWS console, the underlying features in Azure feel like they're incomplete.

Tuesday, April 10, 2018

Integrating SSH with AWS Simple Directory

I had a helluva time trying to get SSH to authenticate against AWS Simple Directory (AD), so I figured I'd jot down some notes about what I finally got to work.

First, I added all public SSH keys to the altSecurityIdentities attribute in AD. Probably not what it's for but it's there and it works!

Second, I added a script to /etc/ssh which fetches the public keys for a particular user:

#!/bin/sh
ldapsearch '(&(objectClass=user)(sAMAccountName='"$1"'))' -H ldap://ad.urbanlogiq.com:3268 -D '***' -w '***' 'altSecurityIdentities' | sed -n '/^ /{H;d};/altSecurityIdentities:/x;$g;s/\n *//g;s/altSecurityIdentities: //gp'

... which was referenced by the /etc/ssh/sshd_config file:

[... snip ...]
AuthorizedKeysCommand /etc/ssh/ldap_keys.sh
AuthorizedKeysCommandUser nobody
[... snip ...]

Then, I installed the libpam-ldapd package (note the trailing d!) The nslcd daemon was configured like so:

# /etc/nslcd.conf
# nslcd configuration file. See nslcd.conf(5)
# for details.

# The user and group nslcd should run as.
uid nslcd
gid nslcd

# The location at which the LDAP server(s) should be reachable.
uri ldap://ad.myhouse.inthemiddleofthestreet.com:3268

# The search base that will be used for all queries.
base ***

# The LDAP protocol version to use.
ldap_version 3

# The DN to bind with for normal lookups.
binddn ***
bindpw ***

# The DN used for password modifications by root.
#rootpwmoddn cn=admin,dc=example,dc=com

# SSL options
#ssl off
#tls_reqcert never
tls_cacertfile /etc/ssl/certs/ca-certificates.crt

# The search scope.
scope sub

# Mappings for Active Directory
# This is the important bit; these fields match up with the fields added by Directory Services for UNIX
pagesize 1000
#referrals no
filter passwd (&(objectClass=person))
map    passwd uid              sAMAccountName
map    passwd homeDirectory    "/home/$sAMAccountName"
map    passwd loginShell       "/bin/bash"
map    passwd gecos            displayName
map    passwd uidNumber        objectSid:S-1-5-21-3623811015-3361044348-30300820
map    passwd gidNumber        objectSid:S-1-5-21-3623811015-3361044348-30300820
# If you wish to override the shell given by LDAP, uncomment the next line
#map    passwd loginShell       "/bin/bash"
filter shadow (&(objectClass=person))
map    shadow uid              sAMAccountName
map    shadow shadowLastChange pwdLastSet
filter group  (objectClass=group)
#map    group  gid              member

Note the attribute map above; the uidNumber and gidNumber maps are needed otherwise things will break when it tries to find your user in the default SimpleDirectory schema. Next, nsswitch.conf needs to be updated to use ldap:

[... snip ...]
passwd:         compat ldap
group:          compat ldap
shadow:         compat ldap
[... snip ...]

And, lastly, /etc/pam.d/common-session needs to be augmented for PAM to create the home directory on first login. Just stuff this line at the end:

session  required pam_mkhomedir.so skel=/etc/skel umask=0022

And that's what I did! I still need to sort out sudo functionality. Maybe that'll be a future update.