github.com/drone/runner-go@v1.12.0/secret/encrypted.go (about) 1 // Copyright 2019 Drone.IO Inc. All rights reserved. 2 // Use of this source code is governed by the Polyform License 3 // that can be found in the LICENSE file. 4 5 package secret 6 7 import ( 8 "context" 9 "crypto/aes" 10 "crypto/cipher" 11 "encoding/base64" 12 "errors" 13 14 "github.com/drone/runner-go/logger" 15 "github.com/drone/runner-go/manifest" 16 17 "github.com/drone/drone-go/drone" 18 ) 19 20 // Encrypted returns a new encrypted secret provider. The 21 // encrypted secret provider finds and decrypts secrets stored 22 // inline in the (yaml) configuration. 23 func Encrypted() Provider { 24 return new(encrypted) 25 } 26 27 type encrypted struct{} 28 29 func (p *encrypted) Find(ctx context.Context, in *Request) (*drone.Secret, error) { 30 logger := logger.FromContext(ctx). 31 WithField("name", in.Name). 32 WithField("kind", "secret") 33 34 // lookup the named secret in the manifest. If the 35 // secret does not exist, return a nil variable, 36 // allowing the next secret controller in the chain 37 // to be invoked. 38 data, ok := getEncrypted(in.Conf, in.Name) 39 if !ok { 40 logger.Trace("secret: encrypted: no matching secret") 41 return nil, nil 42 } 43 44 // if the build event is a pull request and the source 45 // repository is a fork, the secret is not exposed to 46 // the pipeline, for security reasons. 47 if in.Repo.Private == false && 48 in.Build.Event == drone.EventPullRequest && 49 in.Build.Fork != "" { 50 logger.Trace("secret: encrypted: restricted from forks") 51 return nil, nil 52 } 53 54 decoded, err := base64.StdEncoding.DecodeString(string(data)) 55 if err != nil { 56 logger.WithError(err).Debug("secret: encrypted: cannot decode") 57 return nil, err 58 } 59 60 decrypted, err := decrypt(decoded, []byte(in.Repo.Secret)) 61 if err != nil { 62 logger.WithError(err).Debug("secret: encrypted: cannot decrypt") 63 return nil, err 64 } 65 66 logger.Trace("secret: encrypted: found matching secret") 67 68 return &drone.Secret{ 69 Name: in.Name, 70 Data: string(decrypted), 71 }, nil 72 } 73 74 func getEncrypted(spec *manifest.Manifest, match string) (data string, ok bool) { 75 for _, resource := range spec.Resources { 76 secret, ok := resource.(*manifest.Secret) 77 if !ok { 78 continue 79 } 80 if secret.Name != match { 81 continue 82 } 83 if secret.Data == "" { 84 continue 85 } 86 return secret.Data, true 87 } 88 return 89 } 90 91 func decrypt(ciphertext []byte, key []byte) (plaintext []byte, err error) { 92 block, err := aes.NewCipher(key[:]) 93 if err != nil { 94 return nil, err 95 } 96 97 gcm, err := cipher.NewGCM(block) 98 if err != nil { 99 return nil, err 100 } 101 102 if len(ciphertext) < gcm.NonceSize() { 103 return nil, errors.New("malformed ciphertext") 104 } 105 106 return gcm.Open(nil, 107 ciphertext[:gcm.NonceSize()], 108 ciphertext[gcm.NonceSize():], 109 nil, 110 ) 111 }