run remote commands over SSH!

Sometimes I find myself needing to run a few command on a remote machine. In the past I would have SSH’d into the box and hacked away. But, since this isn’t repeatable it’s not ideal. I have a simple alternative. You can setup a script to run command over SSH!

In the example below, I wanted to keep the configuration files in the git repository, but wanted a quick and dirty way to deploy the changes.

The first half of the script copies files, using scp, from the local machine to the remote server.

The second half of the script (starting on line 12) runs commands from the remote machine. The files are moved to the correct locations and Nginx and Haproxy are restarted.

#!/bin/bash

PEM=id_rsa.pub
HOST=ec2-54-234-130-49.compute-1.amazonaws.com

scp -i ~/.ssh/$PEM ./surrogate_pop.conf ubuntu@$HOST:/tmp
scp -i ~/.ssh/$PEM ./haproxy.cfg ubuntu@$HOST:/tmp
scp -i ~/.ssh/$PEM ./traffic_cop.lua ubuntu@$HOST:/tmp
scp -i ~/.ssh/$PEM ./allowed_domains.lua ubuntu@$HOST:/tmp

## These are executed on the remote host
ssh -i ~/.ssh/$PEM ubuntu@$HOST 'bash -s' <<EOF
sudo mv /tmp/traffic_cop.lua /usr/share/nginx/traffic_cop.lua
sudo mv /tmp/allowed_domains.lua /usr/share/nginx/allowed_domains.lua
sudo mv /tmp/surrogate_pop.conf /etc/nginx/sites-enabled/surrogate_pop.conf
sudo service nginx restart

sudo mv /tmp/haproxy.cfg /etc/haproxy/haproxy.cfg
sudo service haproxy restart
EOF

Cloudformation ApiGateway and Lambda

Recently, I’ve been excited by serverless technology. I began using the serverless framework for code boilerplate and deployment. After some time using the framework, I began feeling pain. Serverless is an excellent project, but it’s moving very fast. For example, The framework uses cloudformation for resource dependencies such as dynamoDb, ApiGateway, roles and permissions (to name a few). Cloudformation is also moving very fast. Support for ApiGateway was added to cloudformation on April 18th, 2016. As new features are added to cloudformation, you’ll be stuck waiting for serverless to implement features for feature parity. I’ve started using cloudformation direclty and relying on bash scripts for deployment. I’m quite happy with the results.

Cloudformation stack

Once we have a cloudformation template, the AWS cli provides us with everthing we need. Using the AWS CLI we can create the stack like so.

$ aws cloudformation create-stack 
	--stack-name hello-world 
	--template-body file://./cloudformation.json 
	--capabilities CAPABILITY_IAM && 
	aws cloudformation wait stack-create-complete 
		--stack-name hello-world

The first command fires off an async create request to AWS. The second command tells our shell to wait for stack creation to complete.

After that’s complete, we’ll have created a few resources in AWS. =) Next, we’ll need a way to deploy.

Deployment

We have a few tasks for a complete deployment. We should seperate out the lambda depoyment and the ApiGateway deployment, but in this case I did not.

  • Update Lambda Code - Install any dependencies, zip our code, and upload it.
  • Publish a Version - From the latest version, It will tag a copy.
  • Update the alias - Our lambda is pointed to an alias. This will point the lambda to our new version.
  • deploy ApiGateway - Any changes we make to ApiGateway requires a deploy.

The script takes two args. The api-gateway-id and the function-name.

$ ./deploy.sh abc123 hello-word
#!/bin/bash

apiId=$1
functionName=$2
profile=personal


YELLOW='\033[0;33m'
WHITE='\033[0m' # No Color

function zipLambda {
  say "Zipping files." && 
  rm -rf target && 
  mkdir -p target && 
  cp -r *.js package.json target/ && 
  pushd target && 
  npm install --production && 
  zip -r "${functionName}.zip" . && 
  popd
}

function say {
  printf "\n${YELLOW} $@ ${WHITE}\n"
}

function updateLambdaCode {
  say "Uploading new lambda code." && 
  aws lambda update-function-code --function-name $functionName --zip-file "fileb://target/${functionName}.zip" --profile $profile
}

function publishVersion {
  say "Publishing a new version." && 
  aws lambda publish-version --function-name $functionName --profile $profile
}

function updateAlias {
  version=$(aws lambda list-versions-by-function --function-name $functionName --profile personal | grep Version | tail -n 1 | cut -d '"' -f 4) && 
  say "Updating the alias to version ${version}." && 
  aws lambda update-alias --function-name $functionName --function-version $version --name prod --profile $profile
}
function deployApiGatway {
  say "Deploying to Api Gateway." && 
  aws apigateway create-deployment --rest-api-id $apiId --stage-name v1 --profile $profile
}
printf "\n🚀🚀🚀 SHIP IT!!! 🚀🚀🚀 \n\n"
zipLambda && 
  updateLambdaCode && 
  publishVersion && 
  updateAlias && 
  deployApiGatway

Don't be clever stupid

Everyone loves clever, right!?. Well, DONT! A clever solution is technical debt.

Any fool can write code that a computer can understand. Good programmers write code that humans can understand. – Martin Fowler

So why do we do this? I belevie we enjoy knowing something that confuses others. It makes us feel smart. But please avoid this. Avoid this for your app, for your teammates, and for your future self.

ActiveModel::Model

Rails 4 brought us ActiveModel::Model. It provides a light weight interface that’s similar to an ActiveRecord::Base model.

for example, I can create a Person class like so.

class Person
  include ActiveModel::Model
  attr_accessor :name, :age

  validates :name, true

  def save
    ## Do cool stuff here...
  end
end
Loading development environment (Rails 4.2.1)
irb(main):001:0> p = Person.new age: 21
=> #<Person:0x007fc6367193b0 @age=21>
irb(main):002:0> p.valid?
=> false
irb(main):003:0> p.errors
=> #<ActiveModel::Errors:0x007fc638000a68 @base=#<Person:0x007fc6367193b0 @age=21, @validation_context=nil, @errors=#<ActiveModel::Errors:0x007fc638000a68 ...>>, @messages={:name=>["can't be blank"]}>
irb(main):004:0>

This is great for instances where you don’t need a full database backed Active Record model. I’ve used them for form objects and in controllers where I have complex logic.

You can think of these as higher level abstractions above your ActiveRecord classes. Also, be conscious of the dependancy direction. An ActiveModel model can depend on an ActiveRecord model but your ActiveRecord models shouldn’t depend on an ActiveModel model.


Here's a more involved example. Lets say I have 2 ActiveRecord classes `Org` and `User`
class Org < ActiveRecord::Base
  validates :name, presence: true
end
class User < ActiveRecord::Base
  validates :first, :last, presence: true
end

Now I’ll create an ActiveModel model (non database)

Notice the validates_each method… Its going to check each of the ActiveRecord objects and let them raise up any errors to the Signup class.

class Signup
  include ActiveModel::Model
  attr_accessor :first, :last, :name

  validates_each :user, :org do |record, attr, value|
    unless value.valid?
      value.errors.each { |k,v| record.errors.add(k.to_sym, v) }
    end
  end

  ## must return boolean
  def save
    if valid?
      org.save && user.save
    else
      false
    end
  end

  private

    def org
      @org ||= Org.new(name: name)
    end

    def user
      @user ||= User.new(first: first, last: last)
    end
end

Awesome right!!

So why do all this? Well, the single responsibilty states that every class should have responsibility over a single part of the functionality provided by the software, and that responsibility should be entirely encapsulated by the class. ActiveRecord is responsible for persistence to the database. This will keep our classes with a narrow focus and allow us to refactor and create more use cases in the future. I think it’s a win. I find this strategy is generally good for one directional workflows such as signup or in a shopping app cart checkout.

rails configuration

Occasionally I’ll see things like this in a code base.

def api_host
  if Rails.production?
    "http://prod.fake.api.url"
  else
    "http://stag.fake.api.url"
  end
end

I try to avoid writting methods like this. Rails provides a nice way to set environment specific variables.

http://guides.rubyonrails.org/configuring.html#custom-configuration

config/environments/staging.rb

config.api_host = "http://stag.fake.api.url"

config/environments/production.rb

config.api_host = "http://prod.fake.api.url"

So now you can refactor the method to this.

def api_host
  Rails.configuration.api_host
end

Crypto

I’ve been playing around with Public-key cryptography or asymmetric cryptography. With revaltions from Eric Snowden on programs like PRISM, I feel that encryption is more important than ever.

From Wikipedia

Public-key cryptography is a class of cryptographic algorithms which requires two separate keys, one of which is secret (or private) and one of which is public. Although different, the two parts of this key pair are mathematically linked. The public key is used to encrypt plaintext or to verify a digital signature; whereas the private key is used to decrypt ciphertext or to create a digital signature.

There are two main uses for public key crypto.

  1. Public key encryption. A message is encrypted with a recipient’s public key. The message can only be unencrypted by the holder of the private key.

  2. Digital Signature. A message is signed with a the senders private key to generate a cryptographic hash. Using the public key, one can verify the message was indeed sent with the coresponding private key and can ensure the message has not been altered.

Keys

First, let’s generate some keys. From the private key we will also generate the public key. Remember the private and public key are mathematically linked. This is important.

[1] pry(main)> require "openssl"
=> true
[2] pry(main)> private_key = OpenSSL::PKey::RSA.new(2048)
=> #<OpenSSL::PKey::RSA:0x007ff03b379c30>
[3] pry(main)> public_key = private_key.public_key
=> #<OpenSSL::PKey::RSA:0x007ff03c3330b8>

Great. Now we have a key pair. We can write these keys to disk if we like.

## write the private key to disk.
File.open("~/.ssh/private_key", "w+") do |f|
  f.write private_key.to_pem
end
# write the public key to disk.
File.open("~/.ssh/public_key.pem", "w+") do |f|
  f.write public_key.to_pem
end

We can read the key in from key like so.

key = OpenSSL::PKey::RSA.new(File.read("~/.ssh/private_key"))

Public key enctryption

We’ll be encrypting a message with the public key. So it can only be unenctrypted by the owner of the private key.

## Use the public key to encrypt a message
[4] pry(main)> encrypted_data = public_key.public_encrypt("Some private data is here.")
=> "›Ò"lûú¢Ì;ŸÂrúˆ”\ÛZY–4ãiÛµ´<Žì¸«"aáàŒb쮆À!È©ÞBe^Ìe܁ܘXÖ"bUJ°Bí–Ÿ}÷IýŸôQ§HœÅaá¤kxô6A% ëë: Ñ¢ÿ¤$½PŸRéӟ\r>Ž5ÙèYde`Žà½å\öƒÔmÍJš*¦õS9ÒMÕ 7’Îð¹<¯eš®Ž`­W“‘;HZëØÿÞmò*\tL2â`KÈ)O†Ú¯k4Ð\rNó%}êMheßÆåª$V¾~ŽLvœÇ´o¡3âÞât!]-Ȉ¯ãÕý`TÙÍsÿ®(<½¹"

This will result in some unreadable binary data. Next we’ll decrypt this data with the private key.

## Use the private key to decrypt
[5] pry(main)> private_key.private_decrypt(enc)
=> "Some private data is here."

Nice!

The public key can encrypt but cannot decrypt the message. This enctryption only works in one direction. Only the private key can decrypt that message. You can also encrypt messages with a private key. Those messages can be unenctrypted with the public key and the private key.

Asymmetric public/private key encryption is slow and victim to attack in cases where it is used without padding or directly to encrypt larger chunks of data. Typical use cases for RSA encryption involve “wrapping” a symmetric key with the public key of the recipient who would “unwrap” that symmetric key again using their private key.

NOTE - The enctrypted messages are in binary format. If we want to encode the data for transmission accoss the net, we’ll want to use something like base64.

[6] pry(main)> require "base64"
=> true
[7] pry(main)> enc_string = Base64.encode64(encrypted)
=> "iRBt6WHFYP2sn2Qv+qs16js/EJqBGaTWyxUH7iI/aj3UEw1oUHHbrFs/705W\nP+8dJ77p5gAaBpS/spCYLu/strU3uN06DTOh3neTcyDQrpIL5Zqs0Gl6/76m\nOQFGi18khnwWPAyW4+uVcZiQmZU9M0tlWywwNlkVoKAwkFlwkYF07YZazfCY\nMrAoQ6nusfjqjfU7HQeQKSCnMrBkzInsqan0PUm+UuGCMbxpQMdPA1de2nHB\neMs7OR7Pd5q5T93z240Iacjtwo/CV3Tcr1EyrfCcx05Jp4FKi9DPJf33asPx\noJ7J2XNa3QXqEbisMGT/b+6QZDm/LbfZXKuCIDYOjA==\n"

This works for small messages but if you try and encrpt a string larget than your key… you’ll hit an errors. You could break up the string into smaller chunks and encrypt each chunk individually. But this is not secure. This is what cypher block chaining is for. Below is an example.

cipher      = OpenSSL::Cipher.new 'AES-128-CBC'
cipher.encrypt
iv          = cipher.random_iv
pwd         = 'tRiSsmiTp'
salt        = OpenSSL::Random.random_bytes 16
iter        = 20000
key_len     = cipher.key_len
digest      = OpenSSL::Digest::SHA256.new

key = OpenSSL::PKCS5.pbkdf2_hmac(pwd, salt, iter, key_len, digest)
cipher.key = key

File.open("enc-text.txt",'w') do |enc|
  File.open("./plain.txt") do |f|
     loop do
       r = f.read(4096)
       break unless r
       enc << cipher.update(r)
     end
     enc << cipher.final
  end
end

Digital Signature

Asymmetric digital signatures is a great way to verify integrity and authenticity of data. Create a keypair, send the public key to your receivers, and use this method to create a digital signature. By combining the data and the public key, you can verify that the signature was created by the owner of the private key.

require "openssl"

data = "A small brown fox."


digest = OpenSSL::Digest::SHA256.new
# To list available digests:
#OpenSSL::Digest.constants

signature = private_key.sign(digest, data)

public_key.verify(digest, signature, data)
# => true
public_key.verify(digest, signature, data + "altered")
# => false
public_key.verify(digest, "altered" + signature, data)
# => false

More

Using openssl library directly we can encrypt a file.

openssl aes-256-cbc -a -e -in source-file.txt -out enc-file.txt -k private_key

And to decrypt the file.

openssl aes-256-cbc -d -a -in enc-file.txt -out unenc-file.txt -k private_key

http://ruby-doc.org/stdlib-2.0/libdoc/openssl/rdoc/OpenSSL.html#label-PBKDF2+Password-based+Encryption

ssh config

I’m in and out of servers all day. One thing I’ve found helpful is a ssh config file. Create a file and place it ~/.ssh/config. You can add as many entries as you like.

Host s3-rsync
  HostName ec2-54-203-43-190.us-west-2.compute.amazonaws.com
  User ec2-user
  IdentityFile "~/.ssh/private-key-location"

Host: A friendly name/handle which you’ll use.

HostName: The remote server address you’ll be connecting to.

User: The user you want to connect as.

IdentityFile: The private key to authenticate with.

Once its all setup you can connect by typing: ssh s3-rsync

This is the same as: ssh -i ~/.ssh/bs2-deploy ec2-user@ec2-54-203-43-190.us-west-2.compute.amazonaws.com.

Standard rails create action

Rails has taught me some really good best practices. Let’s look at a default rails create action

def create
  @post = Post.new(post_params)
  respond_to do |format|
    if @post.save
      format.html { redirect_to @post, notice: 'Post was successfully created.' }
    else
      format.html { render :new }
    end
  end
end

I try not to deviate too much from this and nor should you. If @post.save returns true. return a 201 status code. If @post.save returns false re-render the :new action. So you can let the user fix the form.

Often I will see things like this.

def create
  if params[:something]
    @post = Post.create(post_params)
  else
    @post = Post.create(other_params)
  end
  redirect_to posts_path
end

At first glance this looks clean. But if you look closer. There is a subtle problem here. If the post object fails validation and fails to create, The action redirects to the index action where all new instaces are creating. The @post object has lost any knowlege of the params and it will not get to oportunity to display the errors from the object. You’ll have to resort to things like flash[:notice] = "@post.errors.full_messages.join()"… ugh.

Active record gives us a nice interface for displaying errors on an object.

class Post < ActiveRecord::Base
  validates :title, presence: true
end
irb(main):001:0> p = Post.new
=> #<Post id: nil, title: nil, body: nil, created_at: nil, updated_at: nil>
irb(main):002:0> p.valid?
=> false
irb(main):003:0> p.errors
=> #<ActiveModel::Errors:0x007fe0ca9e4b68 @base=#<Post id: nil, title: nil, body: nil, created_at: nil, updated_at: nil>,
@messages={:title=>["can't be blank"]}>
irb(main):004:0>

When you call @post.save OR @post.valid? errors are added to the @post object so they can be displayed within the form.

Digging even deeper… Check out ActiveModel::Model. It will give you this same object interface without needing database backed model. Powerful stuff.

angularjs

Lately I’ve been writing a lot of angularjs. At my work, we had a great debeate.. which client side framework should we use. It came down to angularjs or ember. Ultimately, we choose angular. I’m happy we did. Angularjs is awesome. I would have been just as happy to settle with ember. Two way binding is a game changer.

Rails is great, BUT, I feel that, in any rails app, you end up creating interfaces that are a reflection of your database. Adding a client side framework, you’re free to create interfaces that are decoupled from your backend.

Message of the Day

Lately I’ve been doing a lot of server administration. It can be a lot of fun automating systems. One thing I’ve found super valuable is to setup a “message of the day” file. This will display immediately after login and can be found in /etc/motd. I like to put notes/documentation here. For example, I’ll put in how to restart redis, how to tag a deploy, or the path to the app.

Hosting a static site on an S3 bucket

I love the recent shift from dynamic sites to static sites. This doesn’t work for all sites. But why have a blog that gets dynamically build on each request. It’s Not needed.

Amazon will host static sites on an S3 bucket and its dead simple. Awesome!

  1. Create a bucket and set as public host.
  2. Upload files and make them public.
  3. Profit.

Migrate a Single Database Migration

rails console
require "db/migrate/20121130134444_add_column_backorder_to_orders.rb"
AddColumnBackorderToOrders.up

Convert a Date String to Ruby Date

Date.parse '2013/1/15'

DateTime.parse('2013/1/15'+'-23:59:59-6:00')

Form helper from console

From the rails console.

helper.text_field :object, :name

"<input id="object_name" name="object[name]" size="30" type="text" />"

Set default value in rails model

I like to set default values in my models. This is the method I like to use.

def after_initialize
  if new_record?
    self.upper_quantity ||= 0.0
  end
end

Failed to Connect to a Master Node at Localhost:27017

Everytime my server looses power, Mongo has trouble restarting. These commands fixes the problem.

sudo rm /var/lib/mongodb/mongod.lock
sudo -u mongodb mongod -f /etc/mongodb.conf --repair
sudo service mongodb restart

Install Elastic Search on Ubuntu

Update Package Manager

sudo apt-get update

Install JRE

sudo apt-get install openjdk-7-jre-headless -y

Install Elastic Search

wget http://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-0.20.2.tar.gz -O elasticsearch.tar.gz
tar -xf elasticsearch.tar.gz
rm elasticsearch.tar.gz
sudo mv elasticsearch-* elasticsearch
sudo mv elasticsearch /usr/local/share

Install the Service Wrapper

curl -L http://github.com/elasticsearch/elasticsearch-servicewrapper/tarball/master | tar -xz
sudo mv *servicewrapper*/service /usr/local/share/elasticsearch/bin/
rm -Rf *servicewrapper*
sudo /usr/local/share/elasticsearch/bin/service/elasticsearch install
sudo ln -s `readlink -f /usr/local/share/elasticsearch/bin/service/elasticsearch` /usr/local/bin/elasticsearch
sudo service elasticsearch start
curl http://localhost:9200

Ubuntu ip-address

sudo vim /etc/network/interfaces
# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).

# The loopback network interface
auto lo
iface lo inet loopback

# The primary network interface
auto eth0
iface eth0 inet static
address 192.168.1.4
netmask 255.255.255.0
gateway 192.168.1.1

Add public ssh key to server

cat ~/.ssh/id_rsa.pub | ssh user@hostname 'cat >> .ssh/authorized_keys'