Category Archives: Tech

Four responsibilities of a CTO

Brad Feld recently shared “what does a CTO do”. While several points referred to much larger companies that didn’t feel applicable to me — for example, I’m not nearly as outward facing or as involved in sales — it was helpful to read. Mostly, I was glad that it led me to think more deeply about how I view my responsibilities as CTO at a smaller, series A company. I see my responsibilities falling into 4 buckets: people, ideas, the business, and dev-ops:

  1. People
    • We like the Daniel Pink model: mastery, autonomy, and purpose motivate people. We ask people to self-rate each week on those 3 things. I want developers to feel they’re constantly challenged and growing.
    • I also like the servant leadership / inverted pyramid model: managers support and empower workers. Joel Spolsky tells the story of being in the Israeli army and seeing a sergeant major show him how to scrub a toilet. I like that. (But we’re keeping our cleaning service.)
    • The flow/zone/monastic startup police. If distractions are grenades, jump on the grenades so developers can stay in the zone. If someone has to come out of the zone, I want it to be me.
    • Recruiting, interviewing
  2. Ideas
    • Peer-to-peer: If team A discovers an interesting technology, library, or service, make sure team B knows about it.
    • Outside-in: books, blogs, podcasts, meetups. Scanning the horizon for new technologies, more options. Before we start building something, it’s helpful if someone can say, “Hey, wait, I saw a package/library/service that will do that” or “Such-and-such company modeled that data or process this way.”
    • Teaching/mentoring: We don’t do formal pairing, but it’s not uncommon to sit down with a developer to code something and hear, “I didn’t know you could do that”, or “I didn’t think about that constraint”. And it goes both ways. I also forward articles on programming concepts, technologies, libraries, etc.
    • Advisor to the team leads on technology choices and architecture
  3. Business
    • Advisor to CEO — provide 2nd opinion on general management decisions.
    • Opinionated on business model and strategy.
    • Able to articulate business constraints to the engineering team, e.g. “We only want to build this if it’s in X amount of time, under XYZ circumstances”, “This doesn’t meet the needs of the business.”
  4. DevOps
    • Head of DevOps, which meets the dual role of 1. supporting people (make sure the Vagrant box is working so developers don’t have to fiddle with their dev environments) and 2. supporting the business (the site’s up, it’s fast, we have backups, we’re protecting IP and assets, etc.)

How to Password Protect Redmine with Apache, mod_perl, and Redmine.pm

Today I needed to password-protect a Redmine installation. I’ve typically used mod_auth_mysql for similar projects, but Redmine uses a salted password format that’s incompatible with mod_auth_mysql. So, I turned to Apache/Perl authentication, a first for me (I rarely touch Perl) and was able to make it work.

  1. Install mod_perl, and the DBI, MySQL, and Digest (SHA1) Perl modules.
    $ apt-get install libapache-dbi-perl libapache2-mod-perl2 libdbd-mysql-perl libdigest-sha1-perl
    
  2. Copy Redmine.pm to the appropriate Perl location.
    $ cd /path/to/redmine
    $ mkdir -p /usr/lib/perl5/Apache/Authn
    $ cp extra/svn/Redmine.pm /usr/lib/perl5/Apache/Authn/
    
  3. Perhaps I’m not using Redmine’s projects/members/permissions correctly, but I had to patch Redmine.pm to get it to work for me. I greatly simplified the SQL statement used to authenticate a user. There’s no sense of permissions; it’s simply a yes/no for authenticated users.
    --- Redmine.pm	2011-11-12 17:33:10.000000000 -0700
    +++ Redmine.richardkmiller.pm	2011-11-12 17:37:26.000000000 -0700
    @@ -148,16 +148,11 @@
       my ($self, $parms, $arg) = @_;
       $self->{RedmineDSN} = $arg;
       my $query = "SELECT 
    -                 hashed_password, salt, auth_source_id, permissions
    -              FROM members, projects, users, roles, member_roles
    +                 hashed_password, salt
    +              FROM users
                   WHERE 
    -                projects.id=members.project_id
    -                AND member_roles.member_id=members.id
    -                AND users.id=members.user_id 
    -                AND roles.id=member_roles.role_id
    -                AND users.status=1 
    -                AND login=? 
    -                AND identifier=? ";
    +                    users.status=1 
    +                AND login=?";
       $self->{RedmineQuery} = trim($query);
     }
     
    @@ -336,11 +331,12 @@
       }
       my $query = $cfg->{RedmineQuery};
       my $sth = $dbh->prepare($query);
    -  $sth->execute($redmine_user, $project_id);
    +  $sth->execute($redmine_user);
     
       my $ret;
    -  while (my ($hashed_password, $salt, $auth_source_id, $permissions) = $sth->fetchrow_array) {
    -
    +  while (my ($hashed_password, $salt) = $sth->fetchrow_array) {
    +      my $permissions = ":commit_access";
    +      my $auth_source_id = 0;
           unless ($auth_source_id) {
     	  			my $method = $r->method;
               my $salted_password = Digest::SHA1::sha1_hex($salt.$pass_digest);
    
  4. Configure and restart Apache.
    <virtualhost *:80>
        ServerName example.com
        DocumentRoot "/var/www/sites/example.com/public"
        RailsEnv production
    
        PerlLoadModule Apache::Authn::Redmine
    
        <directory "/var/www/sites/example.com/public">
            AuthType basic
            AuthName "Private Area"
            Require valid-user
            PerlAccessHandler Apache::Authn::Redmine::access_handler
            PerlAuthenHandler Apache::Authn::Redmine::authen_handler
            RedmineDSN "DBI:mysql:database=my_database;host=localhost"
            RedmineDbUser my_db_user
            RedmineDbPass my_db_password
        </directory>
    </virtualhost>
    

By the way, I’m running Ubuntu 11.10 (oneiric), Apache 2.2, MySQL 5.1, and Redmine 1.2.2.

Script to enable/disable SOCKS proxy on Mac OS X

I’m working in a Starbucks today and, as usual on the road, used SSH and SOCKS to browse the Internet securely, but today I decided to take it a step further and automate the process with a shell script. Here’s the script, for what it’s worth:

#!/bin/bash
disable_proxy()
{
        networksetup -setsocksfirewallproxystate Wi-Fi off
        networksetup -setsocksfirewallproxystate Ethernet off
        echo "SOCKS proxy disabled."
}
trap disable_proxy INT

networksetup -setsocksfirewallproxy Wi-Fi 127.0.0.1 9999
networksetup -setsocksfirewallproxy Ethernet 127.0.0.1 9999
networksetup -setsocksfirewallproxystate Wi-Fi on
networksetup -setsocksfirewallproxystate Ethernet on
echo "SOCKS proxy enabled."
echo "Tunneling..."
ssh -ND 9999 MYHOST.macminicolo.net

Instructions:

  1. Save this to a file. I saved it to “/Users/richard/bin/ssh_tunnel”.
  2. Make it executable and run it.
    $ chmod a+x /Users/richard/bin/ssh_tunnel
    $ /Users/richard/bin/ssh_tunnel
    
  3. It creates an SSH tunnel to my dedicated server at macminicolo.net and routes Internet traffic through that server.
  4. Hit Control-C to quit. The proxy is disabled. No need to fiddle with Network Preferences manually.

UPDATE March 18, 2011: I haven’t tried it, but Sidestep appears to be a free Mac OS X app that will enable SSH tunneling automatically when you connect to an insecure network.

Script to enable/disable DMZ on Linksys and Verizon routers

Your home Internet router gives you some protection against direct attacks on your computer by keeping your home network safely encapsulated. Each of your home computers can access the Internet (this is called NAT), but no outsider can access your computers directly. Outsiders only see the router. However, sometimes you want your computer to be “fully” online. Enter the “DMZ” feature of your router. Your router’s DMZ allows one of your computers to be fully exposed to the Internet (for better or worse).

Reasons to enable your DMZ:

  • Access your files while away from home.
  • Serve web pages from your computer.
  • Make BitTorrent transfers faster. BitTorrent transfers are usually faster when your computer is directly exposed to the Internet.

For my work at FamilyLink.com, I develop directly on my local machine. While working on our Facebook application, I need to allow Facebook servers to directly access my machine. (When you use a Facebook app, you’re accessing Facebook’s servers and Facebook servers are, in turn, accessing the developer’s server via a callback URL. While working on our Facebook app, Facebook directly accesses my local machine.) This requires me to open my machine to the DMZ.

Reasons not to enable your DMZ:

  • Your computer is more likely to be hacked
  • Your private data is more likely to be accessed

If you enable your DMZ, know which services are enabled on your machine and which files and data are being shared. There may be files you’re comfortable sharing on your local network that you wouldn’t want to share with the world. Only enable the DMZ as long as necessary.

Enabling the DMZ can be a pain — logging into your router and navigating to the correct setting — so I wrote the following Ruby scripts to make it easy. The first worked with the Linksys router I had. (I believe it was a WRT54G.) To use, fill in your router’s IP address and password, and your computer’s hardware address, then type “linksys_dmz.rb on” or “linksys_dmz.rb off” at the command-line. The script looks up your computer’s hardware address in the table of local IP addresses so the IP address can safely change from time to time.

#!/usr/bin/env ruby
# linksys_dmz.rb

router = '10.1.1.1'
user = 'admin'
pass = 'your_password'
hardware_address = '00:23:6C:00:00:00'

leases = `curl -su #{user}:#{pass} http://#{router}/DHCPTable.asp`
leases.scan(%r{'([^']+)', hardware_address}) do |m|
  ip_address = m[0].strip.to_s
  last_digit = ip_address.split('.').last
  if $*[0] == 'open' || $*[0] == 'on'
    post_values = "submit_button=DMZ&change_action=&action=Apply&dmz_enable=1&dmz_ipaddr=#{last_digit}"
    print "Opening DMZ to #{ip_address}\n\n"
  else
    post_values = "submit_button=DMZ&change_action=&action=Apply&dmz_enable=0"
    print "Closing DMZ\n\n"
  end
  `curl -su #{user}:#{pass} -e http://#{router}/DMZ.asp -d '#{post_values}' http://#{router}/apply.cgi`
end

Last year I switched to Verizon FIOS, which came with its own wireless router, so I had to write a new script. Again, fill in the password, then type “verizon_dmz.rb on” or “verizon_dmz.rb off” in Terminal. (This script assumes a 10.1.1.* network. Change it to 192.168.1.* if that’s what you have.)

As a side note, the Verizon router was a bit of beast to automate. It uses a hashed signature to try to enforce JavaScript-enabled browsers. Writing this script required using TamperData, Charles Proxy, and a lot of trial and error to discover which POST data were necessary.

I use this script to open the DMZ before working on our Facebook app, then I close it when I’m done for the day. Eventually, it’d be nice to find a way to enable the DMZ remotely — maybe via email or something.

#!/usr/bin/env ruby
# verizon_dmz.rb

require 'rubygems'
require 'mechanize'
require 'digest/md5'

user = 'admin'
pass = 'your_password'

localhost = `ifconfig`.scan(/inet (\d+\.\d+\.\d+\.\d+).*broadcast 10.1.1.255/).join
router    = localhost.gsub(/\d+$/,'1')

begin
    agent = Mechanize.new
    page = agent.get("http://#{router}:81")
rescue Exception
    abort "Unable to connect to Verizon Router! Check the IP address."
end

form = page.forms[0]
auth_key = form.fields.find {|f| f.name == 'auth_key'}.value
form.fields.find {|f| f.name == 'user_name'}.value = user
form.fields.find {|f| f.name == 'md5_pass'}.value = Digest::MD5.hexdigest(pass + auth_key)
form.fields.find {|f| f.name == 'mimic_button_field'}.value = 'submit_button_login_submit%3A+..'
form.method = "POST"
form.submit

post = {
    'dmz_host_cb_watermark' => '1',
    'dmz_host_ip0' => localhost.split('.')[0],
    'dmz_host_ip1' => localhost.split('.')[1],
    'dmz_host_ip2' => localhost.split('.')[2],
    'dmz_host_ip3' => localhost.split('.')[3],
    'active_page'  => '9013',
    'mimic_button_field' => 'submit_button_login_submit%3A+..',
}

if $*[0] == 'open' || $*[0] == 'on'
   post['dmz_host_cb'] = '1'
   puts "Opening DMZ to #{localhost}"
else
    puts "Closing DMZ"
end

agent.post('/index.cgi', post)