blob: 4865edd97b208d3aa45e69151b043caea8943bb6 [file] [log] [blame]
James E. Blairc49e5e72017-03-16 14:56:32 -07001#!/usr/bin/env python
2
3# Licensed under the Apache License, Version 2.0 (the "License"); you may
4# not use this file except in compliance with the License. You may obtain
5# a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations
13# under the License.
14
15import argparse
16import os
17import subprocess
18import sys
19import tempfile
20from six.moves import urllib
21
22DESCRIPTION = """Encrypt a secret for Zuul.
23
24This program fetches a project-specific public key from a Zuul server and
25uses that to encrypt a secret. The only pre-requisite is an installed
26OpenSSL binary.
27"""
28
29
30def main():
31 parser = argparse.ArgumentParser(description=DESCRIPTION)
32 parser.add_argument('url',
33 help="The base URL of the zuul server and tenant. "
34 "E.g., https://zuul.example.com/tenant-name")
35 # TODO(jeblair,mordred): When projects have canonical names, use that here.
36 # TODO(jeblair): Throw a fit if SSL is not used.
37 parser.add_argument('source',
38 help="The Zuul source of the project.")
39 parser.add_argument('project',
40 help="The name of the project.")
41 parser.add_argument('--infile',
42 default=None,
43 help="A filename whose contents will be encrypted. "
44 "If not supplied, the value will be read from "
45 "standard input.")
46 parser.add_argument('--outfile',
47 default=None,
48 help="A filename to which the encrypted value will be "
49 "written. If not supplied, the value will be written "
50 "to standard output.")
51 args = parser.parse_args()
52
53 req = urllib.request.Request("%s/keys/%s/%s.pub" % (
54 args.url, args.source, args.project))
55 pubkey = urllib.request.urlopen(req)
56
57 if args.infile:
58 with open(args.infile) as f:
59 plaintext = f.read()
60 else:
61 plaintext = sys.stdin.read()
62
63 pubkey_file = tempfile.NamedTemporaryFile(delete=False)
64 try:
65 pubkey_file.write(pubkey.read())
66 pubkey_file.close()
67
68 p = subprocess.Popen(['openssl', 'rsautl', '-encrypt',
69 '-oaep', '-pubin', '-inkey',
70 pubkey_file.name],
71 stdin=subprocess.PIPE,
72 stdout=subprocess.PIPE)
73 (stdout, stderr) = p.communicate(plaintext)
74 if p.returncode != 0:
75 raise Exception("Return code %s from openssl" % p.returncode)
76 ciphertext = stdout.encode('base64')
77 finally:
78 os.unlink(pubkey_file.name)
79
80 if args.outfile:
81 with open(args.outfile, "w") as f:
82 f.write(ciphertext)
83 else:
84 print(ciphertext)
85
86
87if __name__ == '__main__':
88 main()