#!/usr/bin/env python # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import argparse import base64 import os import subprocess import sys import tempfile # we to import Request and urlopen differently for python 2 and 3 try: from urllib.request import Request from urllib.request import urlopen except ImportError: from urllib2 import Request from urllib2 import urlopen DESCRIPTION = """Encrypt a secret for Zuul. This program fetches a project-specific public key from a Zuul server and uses that to encrypt a secret. The only pre-requisite is an installed OpenSSL binary. """ def main(): parser = argparse.ArgumentParser(description=DESCRIPTION) parser.add_argument('url', help="The base URL of the zuul server and tenant. " "E.g., https://zuul.example.com/tenant-name") # TODO(jeblair,mordred): When projects have canonical names, use that here. # TODO(jeblair): Throw a fit if SSL is not used. parser.add_argument('source', help="The Zuul source of the project.") parser.add_argument('project', help="The name of the project.") parser.add_argument('--infile', default=None, help="A filename whose contents will be encrypted. " "If not supplied, the value will be read from " "standard input.") parser.add_argument('--outfile', default=None, help="A filename to which the encrypted value will be " "written. If not supplied, the value will be written " "to standard output.") args = parser.parse_args() req = Request("%s/keys/%s/%s.pub" % ( args.url, args.source, args.project)) pubkey = urlopen(req) if args.infile: with open(args.infile) as f: plaintext = f.read() else: plaintext = sys.stdin.read() pubkey_file = tempfile.NamedTemporaryFile(delete=False) try: pubkey_file.write(pubkey.read()) pubkey_file.close() p = subprocess.Popen(['openssl', 'rsautl', '-encrypt', '-oaep', '-pubin', '-inkey', pubkey_file.name], stdin=subprocess.PIPE, stdout=subprocess.PIPE) (stdout, stderr) = p.communicate(plaintext.encode("utf-8")) if p.returncode != 0: raise Exception("Return code %s from openssl" % p.returncode) ciphertext = base64.b64encode(stdout) finally: os.unlink(pubkey_file.name) if args.outfile: with open(args.outfile, "wb") as f: f.write(ciphertext) else: print(ciphertext.decode("utf-8")) if __name__ == '__main__': main()