oh that makes more sense
#! /usr/bin/perl -Tw
=head1 NAME
auto-secns.pl - generate some ~/.ssh/authorized_keys file
=head1 SYNOPSIS
(Either run it and hope for the best, or pass the filenames
~/keys/*.pub as arguments.)
=head1 DESCRIPTION
Generates an authorized_keys file based on a set of SSH public keys in
a 'keys' directory, so the holders of the private keys can drop in and
update their zone files.
This one is designed to be run manually when you get a new
subscriber's public key file.
=head2 Alternative file naming schemes
I considered
=over 4
=item - filename represents zone, comment has admin address
You can't get the admin address if the file is broken, and the zones
belonging to one admin are scattered.
=item - filename represents admin, comment has one zone
This seems sensible, except for some inconvenience when the admin has
several zones which are often updated together.
=item - filename represents admin, comment has colon-separeated zone list
I started off with this idea, and I'm sure there's a good reason why I
changed my mind, I just forget what it was.
It is a little inconvenient that the admin would have to update all
zones at once, but if that's a problem he can invent another email
address.
=back
Ah what the foo, I've allowed either of the second two.
=head2 Output file
It will contain lines of the form (I've changed the options)
command="./write-zone.pl t8o.org t80.org",no-port-forwarding,no-pty KEY matthew@fruitcake.demon.co.uk
The last field is again the admin address as a comment, it's just for
debugging really.
=head2 Generating key files
I'm assuming you're using OpenSSH v3 or thereabouts. My set of
commands went something like,
ssh-keygen -t rsa -C t8o.org:t80.org -f t8o.org
ssh-keygen -t rsa -C leete.org.uk -f leete.org.uk
cat *.pub > tmp
rm *.pub
mv tmp matthew@fruitcake.demon.co.uk.pub
Each ssh-keygen will generate two files, foo and foo.pub . The first
is the private key file. You can set a password on it or not, as the
mood takes you - read the docs, know the risks. The second is the
public key file, which is what you need to send to your proposed
secondary nameservers so they can let you in.
The filenames of these two files just provide a contact address in
case of difficulty, and ensure that your filename doesn't clash with
someone else on the same secondary box. I suppose it should be the
same as the one on your SOA record, like anyone cares.
Once you've generated the private file you can rename it to suit
yourself, and if you have multiple public keys (ie. multipl zones) you
can stick them all in the same file.
The comment on each key is the name of the zone it controls.
The key type is set for the SSH2 protocol, RSA. Other types can be
supported if you like.
Reusing authentication keys used for some other purpose may be asking
for trouble, I can't see any reason why you would need to.
=head2 Clashes in email space, domain space and key space
Basically they're not tolerated. You can put multiple public zone keys
in one file under a given email address, but there must be a
one-to-one mapping between zones and key pairs.
=head1 USING IT
Currently the command you request with ssh is ignored. I suggest you
disable all the bells and whistles, like this:
ssh -T -a -x -i mykeys/leete.org.uk autons@toy.ddts.net < zones/leete
Options, in order, avoid requesting a pty, agent forward or X11 forward: you'll get none. Use the specified
=head1 AUTHOR & LICENCE
Copyright (C) 2001 Matthew Astley, all rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
=head1 CREDIT
I think the first site to push me towards using ssh keys in this way
was L<http://www.ucolick.org/~sla/ssh/sshcron.html>.
Thanks also to D. J. Bernstein of L<http://cr.yp.to/> for his cool
toys.
=head1 BUGS
You bet! Let me know if you find one, eh?
=head1 VERSION
$Id: auto-secns.pl,v 1.9 2002/07/07 03:51:27 mca1001 Exp $
=cut
# Everyone knows what the GPL is these days. The lawyers can argue
# about where you get the terms and conditions, this program's quite
# big enough without 17k of extra guff.
use strict;
use vars qw($home %failures @keyfiles $vsn $zonedir);
$vsn = q$Revision: 1.9 $;
#($home = $0) =~ s:/[^/]*$::;
$home = "."; # work in the current directory
$zonedir = "$home/root";
if (@ARGV) {
@keyfiles = @ARGV;
} else {
my $keydir = "$home/keys";
opendir KEYDIR, $keydir or die "Failed to scan directory $keydir: $!";
@keyfiles = map { "$keydir/$_" } grep /\.pub$/, readdir KEYDIR;
closedir KEYDIR;
die "Found no public keys in $keydir\n" unless @keyfiles;
}
# %failures: key = contact addr or empty string if unknown,
# value = [ error, error ... ]
my %zones; # key = zone.domain.name, value = ssh key string as below
my %keys; # key = "ssh-rsa AAAAB3blahblah=", value = admin address
my %key_zones; # key = ssh key string, value = [ zone, zone ... ]
# nb. initially values in %key_zones have only one item in the list,
# but this may change.
foreach my $pubfile (@keyfiles) {
die "Bogus filename '$pubfile'"
unless $pubfile =~ m:^(.*?)([^/]*)\.pub$:;
my ($basedir, $admin) = ($1, $2);
# Read in the public key
if (! open KEY, $pubfile) {
oops($admin, "Failed to read $pubfile: $!");
next;
}
my @lines = <KEY>;
close KEY;
if (@lines == 0) {
oops($admin, "No lines in key file $pubfile");
next;
}
# Extraction & sanity check
foreach my $pubkey (@lines) {
if ($pubkey =~ /^(ssh-rsa\s+\S+)\s+([:\w.-]+)$/) {
my ($key, $zones) = ($1, $2);
# TODO: check the zone for sanity
# TODO: check the zone has us delegated
# Check reused pub key, store
if (defined $keys{$key}) {
oops($admin, "Duplicate key from $keys{$key}: $key");
next;
}
$keys{$key} = $admin;
$key_zones{$key} = [];
foreach my $zone (split /:/, $zones) {
# Check for dup zone, store
if (defined $zones{$zone}) {
my $other = $zones{$zone};
$other = $keys{$other} || '[unspecified]';
oops($admin, "Found duplicate of $zone from $other");
next;
}
$zones{$zone} = $key;
push @{ $key_zones{$key} }, $zone;
}
} else {
oops($admin, "Incomprehensible line at $.");
}
}
}
oops("[check]", "Oh dear, the key counts don't match")
unless (scalar keys %keys) == (scalar keys %key_zones);
# Generate the auth keys list in the appropriate format
my @authfile = ();
foreach my $key (keys %key_zones) {
my @zones = @{ $key_zones{$key} };
if (! @zones) {
oops("[generate]", "No zones for key '$key'");
next;
}
my @badzones = grep /[^a-z0-9-.]/i, @zones;
if (@badzones) {
oops("[generate]", "Bogus zone under key $key");
next;
}
my $cmd = join " ", "./write-zone.pl", @zones;
my $admin = $keys{$key} || '[unspecified]';
if ($admin =~ /\s/) {
oops("[generate]", "Bogus admin name '$admin'");
next;
}
push @authfile,
("command=\"$cmd\",".
"no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ".
"$key $admin\n");
}
# Report the failures all at once at the end
if (scalar keys %failures) {
die(join "\n",
"Problems found by $vsn",
(map { join "\n\t", " $_:", @{$failures{$_}} } sort keys %failures),
"");
}
# oops() has no useful effect from now
# Otherwise, write out a new auth file
my $authfile = "$home/authorized_keys.new";
open AUTHS, ">$authfile" or die "Can't create $authfile: $!";
print AUTHS join "", @authfile or die "Write to $authfile failed: $!";
close AUTHS;
# Check for obselete zone files
if (opendir ZONES, $zonedir) {
my %files;
@files{grep s/\.djbdns$//, readdir ZONES} = ();
closedir ZONES;
foreach my $file (keys %files) {
warn "Warning: Spare file $zonedir/$file\n"
unless defined $zones{$file};
}
foreach my $zone (keys %zones) {
warn "Warning: Zone file $zonedir/$zone.djbdns doesn't exist yet\n"
unless exists $files{$zone};
}
} else {
warn "Can't check for obselete zone files in $zonedir: $!\n";
}
# rename($authfile, "$home/.ssh/authorized_keys") or die "Rename failed: $!";
print "\nYou'll need to\n mv authorized_keys.new .ssh/authorized_keys\n";
# Mark a problem for later
sub oops {
my ($addr, $prob) = @_;
$failures{$addr} = [] unless defined $failures{$addr};
push @{ $failures{$addr} }, $prob;
}
|
Repository owner Powered by ViewCVS 1.0-dev |
ViewCVS and CVS Help |