svnserve, en tilpasset server

Programmet svnserve er en lettvektsserver som er i stand til å snakke med klienter over TCP/IP ved å bruke en tilpasset, stateful protokoll. Klienter kontakter en svnserve-server ved å bruke URL-er som begynner med svn://- eller svn+ssh://-skjemaet. Denne seksjonen vil forklare de forskjellige måtene å kjøre svnserve på, hvordan klienter autentiserer seg selv ovenfor serveren, og hvordan du setter opp en passende adgangskontroll til depotene dine.

Starte serveren

There are a few different ways to run the svnserve program:

  • Run svnserve as a standalone daemon, listening for requests.

  • Have the Unix inetd daemon temporarily spawn svnserve whenever a request comes in on a certain port.

  • Have SSH invoke a temporary svnserve over an encrypted tunnel.

  • Run svnserve as a Windows service.

svnserve as Daemon

The easiest option is to run svnserve as a standalone daemon process. Use the -d option for this:

$ svnserve -d
$               # svnserve is now running, listening on port 3690

Når svnserve kjøres i daemon-modus, kan du bruke valgene --listen-port= og --listen-host= for å sette den eksakte porten og servernavn som den skal bindes til:

Når svnserve-programmet kjører, gjør det alle depotene på systemet tilgjengelig på nettverket. En klient må spesifisere en absolutt sti i depot-URLen. Hvis for eksempel et depot ligger i /usr/local/depoter/prosjekt1, kan en klient nå det via svn://server.example.com/usr/local/depoter/prosjekt1. For å øke sikkerheten kan du angi -r-valget til svnserve som begrenser den til å kun ekportere depoter som ligger under denne stien. For eksempel:

$ svnserve -d -r /usr/local/depot
…

Bruken av -r-valget forandrer plasseringen av roten som programmet bruker på det fjerntliggende filsystemet. Klienter bruker dermed URLer som har fjernet denne delen av stien, noe som gir mye kortere (og mindre avslørende) URLer:

$ svn checkout svn://server.example.com/prosjekt1
…

svnserve via inetd

If you want inetd launch the process, then you can pass the -i (--inetd) option:

$ svnserve -i
( success ( 1 2 ( ANONYMOUS ) ( edit-pipeline ) ) )

Når programmet blir startet med --inetd-valget, prøver svnserve å snakke med en Subversionklient via standard inn og standard ut ved å bruke en tilpasset protokoll. Dette er den vanlige oppførselen for et program som blir kjørt via inetd. IANA har reservert port 3690 for Subversionprotokollen, så på et Unix-lignende system kan du legge til linjer som dette i /etc/services (hvis de ikke allerede eksisterer):

svn           3690/tcp   # Subversion
svn           3690/udp   # Subversion

Og hvis systemet ditt bruker en klassisk Unix-lignende inetd-daemon, kan du legge denne linjen til /etc/inetd.conf:

svn stream tcp nowait svnbruker /usr/bin/svnserve svnserve -i

Pass på at svnbruker er en bruker som har tilstrekkelige rettigheter til å få tilgang til depotene dine. Når nå en klientforbindelse kommer inn til serveren på port 3690, vil inetd starte en egen svnserve-prosess for å ta seg av den. Du vil selvfølgelig også ønske å legge til -r til konfigurasjonslinja også, for å begrense hvilke depot som eksporteres.

svnserve i en tunnel

En tredje måte å starte svnserve på, er i tunnelmodus, med valget -t. Denne modusen forutsetter at et fjerntjenesteprogram som RSH eller SSH har klart å autentisere som en bruker og nå skal starte en privat svnserve-prosess som denne brukeren. svnserve-programmet oppfører seg normalt (kommuniserer via standard inn og standard ut), og går ut i fra at trafikken blir automatisk omdirigert gjennom en form for tunnel tilbake til klienten. Når svnserve blir startet av en tunnelagent som dette, pass på at den autentiserte brukeren har full skrive- og leseaksess til databasefilene i depotet. Det er hovedsaklig det samme prinsippet som når en lokal bruker får tilgang til depotet via file:///-URLer.

This option is described in much more detail in “Autentisering og autorisasjon via SSH”.

svnserve as Windows Service

If your Windows system is a descendant of Windows NT (2000, 2003, XP, Vista), then you can run svnserve as a standard Windows service. You'll need to define the service using a command-line tool SC.EXE. Much like the inetd configuration line, you must specify an exact invocation of svnserve for Windows to run at start-up time:

C:\> sc create svn
        binpath= "C:\svn\bin\svnserve.exe --service [args]"
        displayname= "Subversion Server"
        depend= Tcpip
        start= auto

This defines a new Windows service named svn, and which executes a particular svnserve.exe command when started. There are a number of caveats in the prior example, however.

First, notice that the svnserve.exe program is always invoked with the --service option. You must always specify this option, and you may not specify other conflicting options such as --daemon, --tunnel, or --inetd. Options such as -r or --listen-port are fine. Second, be careful about spaces when invoking the SC.EXE command: the key= value patterns must have no spaces between key= and exactly one space before the value. Lastly, be careful about spaces in your command-line to be invoked. If a directory name contains spaces (or other characters that need escaping), place the entire inner value of binpath in double-quotes, by escaping them:

C:\> sc create svn
        binpath= "\"C:\program files\svn\bin\svnserve.exe\" --service [args]"
        displayname= "Subversion Server"
        depend= Tcpip
        start= auto

Once the service is defined, it can stopped, started, or queried using standard GUI tools (The Services administrative control panel), or at the command line as well:

C:\> net stop svn
C:\> net start svn

The service can also be uninstalled (i.e. undefined) by deleting its definition: sc delete svn. Just be sure to stop the service first! The SC.EXE program has many other subcommands and options, run sc /? to learn more about it.

Innebygget autentisering og autorisasjon

Når en klient kobler seg til en svnserve-prosess, skjer de følgende tingene:

  • Klienten velger et spesifikt depot.

  • Serveren går gjennom depotets conf/svnserve.conf-fil og begynner å gjennomføre alle autentiserings- og autorisasjonsregler som er definert i den.

  • Avhengig av situasjonen og autorisasjonsreglene,

    • kan klienten få lov til å foreta forespørsler anonymt, uten noen gang å motta en autentiseringsforespørsel, ELLER

    • klienten kan bli spurt etter autentiseringsinfo til enhver tid, ELLER

    • hvis den opererer i tunnelmodus, vil klienten erklære seg selv som å allerede være eksternt autentisert.

Når dette skrives, vet serveren bare hvordan den skal sende en CRAM-MD5[35]-autentiseringsforespørsel. I hovedsak sender serveren litt data til klienten. Klienten bruker MD5-algoritmen for å lage et fingeravtrykk av de kombinerte dataene og passordet og sender fingeravtrykket som svar. Serveren foretar den samme utregningen med det lagrede passordet for å sjekke at resultatet er identisk. Passordet blir ikke på noe tidspunkt sendt over nettverket.

Det er også selvfølgelig mulig for klienten å bli eksternt autentisert via en tunnelagent, som for eksempel SSH. I dette tilfellet sjekker serveren rett og slett bare brukeren den kjører som, og bruker den som det autentiserte brukernavnet. For mer om dette, se “Autentisering og autorisasjon via SSH”.

Som du allerede har gjettet, er svnserve.conf-fila i et depot den sentrale mekanismen for å kontrollere autentiserings- og autorisasjonsregler. Fila har det samme formatet som andre konfigurasjonsfiler (se “Konfigurasjonsområdet for bruk under kjøring”): Seksjonsnavn er markert med klammeparenteser ([ og ]), kommentarer begynner med hashtegn (#), og hver seksjon inneholder spesifikke variabler som kan settes (variabel = verdi). La oss gå gjennom denne fila og lære hvordan vi bruker dem.

Opprette en brukerfil og område

For øyeblikket har [general]-seksjonen i svnserve.conf alle variablene som du trenger. Start ved å definere en fil som inneholder brukernavn og passord, og et autentiseringsområde:

[general]
password-db = brukerfil
realm = eksempelområde

realm er et navn som du definerer. Det forteller klienter hvilket autentiseringsnavnerom de kobler seg til; Subversionklienten viser det når den spør etter autentiseringsinfo, og bruker det som en nøkkel (sammen med serverens vertsnavn og port) for å lagre legitimasjonsinfo på disken (se “Lagring av klientlegitimasjon”). Variabelen password-db peker til en separat fil som inneholder en liste med brukernavn og passord, som bruker det samme kjente formatet. For eksempel:

[users]
harry = foopassord
sally = barpassord

Verdien i password-db kan være en absolutt eller relativ sti til brukerfila. For mange administratorer er det enkelt å lagre fila i conf/-området i depotet, sammen med svnserve.conf. På den annen side er det mulig at du vil ha to eller flere depoter som deler den samme brukerfila; i så tilfelle bør fila kanskje ligge på en mer offentlig plass. Depotene som deler brukerfila bør også settes opp til å ha samme område (realm) siden brukerlista hovedsaklig definerer et autentiseringsområde. Hvor fila enn ligger, pass på å sette lese- og skriverettighetene på den. Hvis du vet hvilke(n) bruker(e) svnserve vil kjøre som, begrens lesetilgangen til brukerfila etter hva som er nødvendig.

Sette tilgangskontroll

Det er to variabler til som må settes i svnserve.conf-fila, de avgjør hva uautentiserte (anonyme) og autentiserte brukere får lov til å gjøre. Variablene anon-access og auth-access kan settes til verdiene none, read eller write. Ved å sette verdien til none begrenses alle typer tilganger; read tillater bare lesing fra depotet, og write gir fullstendig lese/skrive-tilgang til depotet. For eksempel:

[general]
password-db = userfile
realm = example realm

# anonyme brukere kan bare lese depotet
anon-access = read

# autentiserte brukere kan både lese og skrive
auth-access = write

Oppsettet i dette eksempelet viser standardverdiene som variablene har, i tilfelle du glemmer å definere dem. Hvis du vil være enda mer konservativ, kan du blokkere anonym tilgang fullstendig:

[general]
password-db = brukerfil
realm = eksempelområde

# anonyme brukere forbudt
anon-access = none

# autentiserte brukere kan både lese og skrive
auth-access = write

The server process not only understands these blanket access controls to the repository, but also finer-grained access restrictions placed on specific files and directories within the repository. To make use of this feature, you need to define a file containing more detailed rules, and then set the authz-db variable to point to it:

[general]
password-db = userfile
realm = example realm

# Specific access rules for specific locations
authz-db = authzfile

The syntax of the authzfile file is discussed in detail in “Path-Based Authorization”. Note that the authz-db variable isn't mutually exclusive with the anon-access and auth-access variables; if all the variables are defined at once, then all of the rules must be satisfied before access is allowed.

Autentisering og autorisasjon via SSH

svnserves innebyggede autentisering kan være veldig grei å ha med å gjøre, fordi man ikke trenger å opprette virkelige brukerkontoer på systemet. På den annen side har noen administratorer allerede et veletablert rammeverk for SSH-autentisering på plass. I disse situasjonene har alle brukerne på prosjektet allerede systemkontoer og muligheten til å koble seg til via SSH på servermaskinen.

Det er enkelt å bruke SSH sammen med svnserve. Klienten bruker ganske enkelt URL-skjemaet svn+ssh:// for å koble seg til:

$ whoami
harry

$ svn list svn+ssh://server.example.com/repos/prosjekt
harry@server.example.com's password:  *****

foo
bar
baz
…

I dette eksempelet starter Subversionklienten en lokal ssh-prosess, kobler seg opp mot server.example.com, autentiserer seg som brukeren harry, starter en privat svnserve-prosess på den fjerntliggende maskinen som kjører som brukeren harry. svnserve-kommandoen blir startet i tunnelmodus (-t) og nettverksprotokollen som den bruker blir lagt i tunnel over den krypterte forbindelsen via ssh, tunnelagenten. svnserve vet at den kjører som brukeren harry, og hvis klienten foretar en innlegging, vil det autentiserte brukernavnet bli kreditert som forfatteren av den nye revisjonen.

Den viktige tingen å forstå her er at Subversionklienten ikke kobler seg til en kjørende svnserve-daemon. Denne tilkoblingsmetoden krever ingen daemon, og den legger heller ikke merke til om noen slike finnes. Den stoler fullt og helt på evnen til ssh å starte en midlertidig svnserve-prosess, som avsluttes når nettverksforbindelsen lukkes.

Når du bruker svn+ssh://-URLer til å aksessere et depot, husk at det er ssh-programmet som spør etter autentisering, og ikke svn-klienten. Dette betyr at det er ingen automatisk lagring av passord (se “Lagring av klientlegitimasjon”). Subversionklienten foretar ofte flere tilkoblinger til depotet, selv om brukere vanligvis ikke legger merke til dette på grunn av funksjonen som lagrer passord. Men ved bruk av svn+ssh:// kan brukere bli plaget med at ssh spør etter passord for hver eneste utgående tilkobling. Løsningen er å bruke et separat passordlagringssystem for SSH som for eksempel ssh-agent på et Unix-lignende system eller pageant i Windows.

Når tilkobling skjer gjennom en tunnel, blir autorisering for databasefilene i depotet hovedsaklig kontrollert av tilgangsrettigheter i operativsystemet; det er mye det samme som om Harry aksesserer depotet direkte via en file:///-URL. Hvis flere systembrukere skal aksessere depotet direkte, vil du kanskje plassere dem i en felles gruppe, og alt du trenger å tenke på er å være forsiktig med umask. (Pass på å lese “Støtte for flere metoder for tilgang til depotet”.) Men selv i tilfellet med bruk av tunnel kan svnserve.conf bli brukt til å blokkere tilgang ved å sette auth-access = read eller auth-access = none.[36]

Man skulle tro at historien om SSH ender her, men det gjør den ikke. Subversion lar deg opprette tilpasset tunneloppførsel i kjøringsfila config (se “Konfigurasjonsområdet for bruk under kjøring”). I [tunnels]-seksjonen i config-fila kan du enkelt definere det på denne måten:

[tunnels]
rsh = rsh

Og nå kan du bruke denne nye tunneldefinsjonen ved å bruke et URL-skjema som samsvarer med navnet på den nye variabelen: svn+rsh://server/sti. Ved bruk av det nye URL-skjemaet vil Subversionklienten faktisk kjøre kommandoen rsh server svnserve -t i bakgrunnen. Hvis du inkluderer et brukernavn i URLen (for eksempel svn+rsh://brukernavn@server/sti), vil klienten også ta dette med i kommandoen (rsh brukernavn@server svnserve -t). Men du kan definere nye tunnelskjema til å være mye mer avanserte enn som så:

[tunnels]
joessh = $JOESSH /opt/alternate/ssh -p 29934

Dette eksempelet demonstrerer et par ting. For det første viser det hvordan du lar Subversionklienten kjøre en spesifikk binærfil som oppretter tunnelen (den som ligger som /opt/alternate/ssh med spesifikke valg. I dette tilfellet vil det å aksessere en svn+joessh://-URL starte denne SSH-binærfila med -p 29934 som parameter – nyttig hvis du vil at tunnelprogrammet skal koble seg til en ustandard port.

For det andre viser det hvordan en tilpasset miljøvariabel kan overstyre navnet på et tunnelprogram. Det å sette miljøvariabelen SVN_SSH er en behagelig måte å overstyre den vanlige SSH-tunnelagenten. Men hvis du må ha flere forskjellige overstyringer for forskjellige servere, der hver av dem kanskje kontakter en forskjellig port eller sender et annet sett med parametere til SSH, kan du bruke mekanismen som er demonstrert i dette eksempelet. Hvis vi nå setter miljøvariabelen JOESSH til noe, vil innholdet av denne variabelen overstyre hele innholdet av tunnelvariabelen – $JOESSH vil bli kjørt istedenfor /opt/alternate/ssh -p 29934.

Konfigurasjonstriks i SSH

Det er ikke bare mulig å kontrollere måten klienten starter ssh på, men også å kontrollere oppførselen til sshd på servermaskinen. I denne seksjonen vil vi vise hvordan du kontrollerer den eksakte svnserve-kommandoen som blir kjørt av sshd, og også hvordan du får flere brukere til å dele en enkel systemkonto.

Innledende oppsett

Til å begynne med, finn fram til hjemmekatalogen for kontoen som du skal bruke til å kjøre svnserve. Vær sikker på at kontoen har et offentlig/privat SSH-nøkkelpar installert, og at brukeren kan logge inn via autentisering med offentlig nøkkel. Autentisering via passord vil ikke fungere, siden alle de følgende SSH-triksene baserer seg på bruk av authorized_keys-fila som brukes av SSH.

Hvis den ikke allerede finnes, opprett fila authorized_keys (i Unix er den vanligvis kalt ~/.ssh/authorized_keys). Hver linje i denne fila beskriver en offentlig nøkkel som får lov til å koble seg til. Linjene har vanligvis dette formatet:

  ssh-dsa AAAABtce9euch… bruker@example.com

Det første feltet beskriver nøkkeltypen, det andre feltet er selve den uuencodede nøkkelen, og det tredje feltet er en kommentar. En lite kjent funksjonalitet er at hele linjen kan bli innledet av et command-felt:

  command="program" ssh-dsa AAAABtce9euch… bruker@example.com

Når command-feltet er definert, vil SSH-daemonen kjøre det navngitte programmet istedenfor den typiske svnserve -t-prosessen som Subversionklienten spør etter. Dette åpner døra til en rekke triks på serversiden. I de følgende eksemplene forkorter vi linjene i fila som:

  command="program" TYPE NØKKEL KOMMENTAR

Kontrollere den startede kommandoen

Fordi vi kan spesifisere kommandoen som kjøres på serversiden, er det lett å navngi en spesifikk svnserve-binærfil som skal kjøres og levere et ekstra parameter til den:

  command="/sti/til/svnserve -t -r /virtuell/rot" TYPE NØKKEL KOMMENTAR

I dette eksempelet kan /sti/til/svnserve være et spesiallaget innkapslingsskript rundt svnserve som setter umask-verdien (se “Støtte for flere metoder for tilgang til depotet”). Det viser også hvordan svnserve kan forankres i en virtuell rotkatalog akkurat som man ofte gjør når svnserve kjøres som en daemonprosess. Dette kan gjøres enten ved å begrense adgangen til deler av systemet, eller ganske enkelt spare brukeren for å måtte skrive inn en absolutt sti i svn+ssh://-URLen.

Det er også mulig å la flere brukere dele en enkel konto. Istedenfor å lage en egen systemkonto for hver bruker, lag et offentlig/privat nøkkelpar for hver person. Legg deretter hver offentlig nøkkel inn i authorized_users-fila, en per linje, og bruk valget --tunnel-user:

  command="svnserve -t --tunnel-user=harry" TYPE1 NØKKEL1 harry@example.com
  command="svnserve -t --tunnel-user=sally" TYPE2 NØKKEL2 sally@example.com

Dette eksempelet lar både Harry og Sally få koble seg til den samme kontoen via offentlig nøkkel-autentisering. Hver av dem har en spesiallaget kommando som vil bli kjørt; valget --tunnel-user ber svnserve -t om å gå ut i fra at den spesifiserte verdien er den autentiserte brukeren. Uten --tunnel-user vil det se ut som om alle innlegginger kommer fra en delt systemkonto.

En siste advarsel: Det å gi en bruker tilgang til serveren via en offentlig nøkkel på en delt konto kan fortsatt gi andre former for SSH-tilgang, selv om du har definert command-verdien i authorized_keys. Brukeren kan for eksempel fortsatt få kommandolinjetilgang via SSH, eller være i stand til å utføre X11- eller generell port-forwarding gjennom serveren. For å gi brukeren så lite rettigheter som mulig, vil du kanskje spesifisere et antall begrensningsvalg like etter command:

  command="svnserve -t --tunnel-user=harry",no-port-forwarding,\
           no-agent-forwarding,no-X11-forwarding,no-pty \
           TYPE1 NØKKEL1 harry@example.com


[35] Se RFC 2195.

[36] Note that using any sort of svnserve-enforced access control at all is a bit pointless; the user already has direct access to the repository database.