@@ -2,8 +2,12 @@ package ssh
22
33import (
44 "fmt"
5+ "github.com/semaphoreui/semaphore/db"
6+ "github.com/semaphoreui/semaphore/pkg/random"
7+ "github.com/semaphoreui/semaphore/util"
58 "io"
69 "net"
10+ "path"
711
812 "github.com/semaphoreui/semaphore/pkg/task_logger"
913 "golang.org/x/crypto/ssh"
@@ -95,6 +99,110 @@ func (a *Agent) Listen() error {
9599}
96100
97101func (a * Agent ) Close () error {
98- close (a .done )
102+ if a .done != nil {
103+ close (a .done )
104+ }
99105 return a .listener .Close ()
100106}
107+
108+ func StartSSHAgent (key db.AccessKey , logger task_logger.Logger ) (Agent , error ) {
109+
110+ socketFilename := fmt .Sprintf ("ssh-agent-%d-%s.sock" , key .ID , random .String (10 ))
111+
112+ var socketFile string
113+
114+ if key .ProjectID == nil {
115+ socketFile = path .Join (util .Config .TmpPath , socketFilename )
116+ } else {
117+ socketFile = path .Join (util .Config .GetProjectTmpDir (* key .ProjectID ), socketFilename )
118+ }
119+
120+ sshAgent := Agent {
121+ Logger : logger ,
122+ Keys : []AgentKey {
123+ {
124+ Key : []byte (key .SshKey .PrivateKey ),
125+ Passphrase : []byte (key .SshKey .Passphrase ),
126+ },
127+ },
128+ SocketFile : socketFile ,
129+ }
130+
131+ return sshAgent , sshAgent .Listen ()
132+ }
133+
134+ type AccessKeyInstallation struct {
135+ SSHAgent * Agent
136+ Login string
137+ Password string
138+ Script string
139+ }
140+
141+ func (key * AccessKeyInstallation ) GetGitEnv () (env []string ) {
142+ env = make ([]string , 0 )
143+
144+ env = append (env , fmt .Sprintln ("GIT_TERMINAL_PROMPT=0" ))
145+ if key .SSHAgent != nil {
146+ env = append (env , fmt .Sprintf ("SSH_AUTH_SOCK=%s" , key .SSHAgent .SocketFile ))
147+ sshCmd := "ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null"
148+ if util .Config .SshConfigPath != "" {
149+ sshCmd += " -F " + util .Config .SshConfigPath
150+ }
151+ env = append (env , fmt .Sprintf ("GIT_SSH_COMMAND=%s" , sshCmd ))
152+ }
153+
154+ return env
155+ }
156+
157+ func (key * AccessKeyInstallation ) Destroy () error {
158+ if key .SSHAgent != nil {
159+ return key .SSHAgent .Close ()
160+ }
161+ return nil
162+ }
163+
164+ type KeyInstaller struct {}
165+
166+ func (KeyInstaller ) Install (key db.AccessKey , usage db.AccessKeyRole , logger task_logger.Logger ) (installation AccessKeyInstallation , err error ) {
167+
168+ switch usage {
169+ case db .AccessKeyRoleGit :
170+ switch key .Type {
171+ case db .AccessKeySSH :
172+ var agent Agent
173+ agent , err = StartSSHAgent (key , logger )
174+ installation .SSHAgent = & agent
175+ installation .Login = key .SshKey .Login
176+ }
177+ case db .AccessKeyRoleAnsiblePasswordVault :
178+ switch key .Type {
179+ case db .AccessKeyLoginPassword :
180+ installation .Password = key .LoginPassword .Password
181+ default :
182+ err = fmt .Errorf ("access key type not supported for ansible password vault" )
183+ }
184+ case db .AccessKeyRoleAnsibleBecomeUser :
185+ if key .Type != db .AccessKeyLoginPassword {
186+ err = fmt .Errorf ("access key type not supported for ansible become user" )
187+ }
188+ installation .Login = key .LoginPassword .Login
189+ installation .Password = key .LoginPassword .Password
190+ case db .AccessKeyRoleAnsibleUser :
191+ switch key .Type {
192+ case db .AccessKeySSH :
193+ var agent Agent
194+ agent , err = StartSSHAgent (key , logger )
195+ installation .SSHAgent = & agent
196+ installation .Login = key .SshKey .Login
197+ case db .AccessKeyLoginPassword :
198+ installation .Login = key .LoginPassword .Login
199+ installation .Password = key .LoginPassword .Password
200+ case db .AccessKeyNone :
201+ // No SSH agent or password needed for ansible user with no access key.
202+ default :
203+ err = fmt .Errorf ("access key type not supported for ansible user" )
204+ }
205+ }
206+
207+ return
208+ }
0 commit comments