首页 > 解决方案 > https - 如何让用户通过 ELB 与 Jenkins 建立安全连接?

问题描述

下面是创建 Elastic Load Balancer 作为公共面向jenkins:ecs在 VPC 子网中运行的 jenkins(docker) 的云形成模板:

{
    "AWSTemplateFormatVersion": "2010-09-09",
    "Description": "Jenkins Stack",
    "Parameters":{
        "VpcId": {
            "Type": "AWS::EC2::VPC::Id",
            "Description": "The target VPC Id"

        },
        "SubnetId": {
            "Type": "AWS::EC2::Subnet::Id",
            "Description": "The target subnet Id"
        },
        "KeyName": {
            "Type": "String",
            "Description": "The key pair that is allowed SSH access"
        }
    },
    "Resources":{
        "EC2Instance":{
            "Type": "AWS::EC2::Instance",
            "Properties":{
                "ImageId": "ami-05958d7635caa4d04",
                "InstanceType": "t2.micro",
                "SubnetId": { "Ref": "SubnetId"},
                "KeyName": { "Ref": "KeyName"},
                "SecurityGroupIds": [ { "Ref": "EC2InstanceSecurityGroup"} ],
                "IamInstanceProfile": { "Ref" : "EC2InstanceProfile"},
                "UserData":{
                    "Fn::Base64": { "Fn::Join": ["", [
                        "#!/bin/bash\n",
                        "echo ECS_CLUSTER=", { "Ref": "EcsCluster" }, " >> /etc/ecs/ecs.config\n",
                        "groupadd -g 1000 jenkins\n",
                        "useradd -u 1000 -g jenkins jenkins\n",
                        "mkdir -p /ecs/jenkins_home\n",
                        "chown -R jenkins:jenkins /ecs/jenkins_home\n"
                    ] ] }
                },
                "Tags": [ { "Key": "Name", "Value": { "Fn::Join": ["", [ { "Ref": "AWS::StackName"}, "-instance" ] ]} }]
            }
        },
        "EC2InstanceSecurityGroup":{
            "Type": "AWS::EC2::SecurityGroup",
            "Properties": {
                "GroupDescription": { "Fn::Join": ["", [ { "Ref": "AWS::StackName" }, " ingress security group" ] ] },
                "VpcId": { "Ref": "VpcId" },
                "SecurityGroupIngress": [
                    {
                        "IpProtocol": "tcp",
                        "FromPort": "8080",
                        "ToPort": "8080",
                        "SourceSecurityGroupId": { "Ref": "ElbSecurityGroup"}
                    },
                    {
                        "IpProtocol": "tcp",
                        "FromPort": "22",
                        "ToPort": "22",
                        "CidrIp": "0.0.0.0/0"
                    }
                ],
                "Tags": [ { "Key": "Name", "Value": { "Fn::Join": ["", [ { "Ref": "AWS::StackName" }, "-ec2-sg" ] ] } } ]
            }
        },
        "EC2InstanceProfile": {
            "Type": "AWS::IAM::InstanceProfile",
            "Properties": {
                "Path": "/",
                "Roles": [ { "Ref": "EC2InstanceRole" } ]
            }
        },
        "EC2InstanceRole": {
            "Type": "AWS::IAM::Role",
            "Properties": {
                "AssumeRolePolicyDocument":{
                    "Version": "2012-10-17",
                    "Statement": [
                        {
                            "Effect": "Allow",
                            "Principal": { "Service": [ "ec2.amazonaws.com" ] },
                            "Action": [ "sts:AssumeRole" ]
                        }
                    ]
                },
                "Path": "/",
                "ManagedPolicyArns": [ "arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role" ]
            }
        },
        "ElbSecurityGroup": {
            "Type": "AWS::EC2::SecurityGroup",
            "Properties": {
                "GroupDescription": { "Fn::Join": ["", [ { "Ref": "AWS::StackName" }, " ELB ingress security group" ] ] },
                "VpcId": { "Ref": "VpcId"},
                "SecurityGroupIngress": [
                    {
                        "IpProtocol": "tcp",
                        "FromPort": "80",
                        "ToPort": "80",
                        "CidrIp": "0.0.0.0/0"
                    }
                ],
                "Tags": [ { "Key": "Name", "Value": { "Fn::Join": ["", [ { "Ref": "AWS::StackName" }, "-elb-sg" ] ] } } ]
            }
        },
        "ElasticLoadBalancer": {
            "Type": "AWS::ElasticLoadBalancing::LoadBalancer",
            "Properties": {
                "CrossZone": "false",
                "SecurityGroups": [ { "Ref": "ElbSecurityGroup" } ],
                "Listeners": [
                    {
                        "LoadBalancerPort": "80",
                        "InstancePort": "8080",
                        "Protocol": "http"
                    }

                ],
                "Instances": [ { "Ref": "EC2Instance"} ],
                "Subnets": [ { "Ref": "SubnetId"} ]
            }
        },
        "EcsCluster": {
            "Type": "AWS::ECS::Cluster"
        },
        "EcsTaskDefinition": {
            "Type": "AWS::ECS::TaskDefinition",
            "Properties": {
                "ContainerDefinitions": [
                    {
                        "Name": "jenkins",
                        "Image": "somedockeracct/jenkins:ecs",
                        "Memory": 500,
                        "PortMappings": [ 
                            { 
                                "ContainerPort": 8080, 
                                "HostPort": 8080 
                            },
                            { 
                                "ContainerPort": 50000, 
                                "HostPort": 50000 
                            }
                        ],
                        "MountPoints": [
                            {
                                "SourceVolume": "docker",
                                "ContainerPath": "/var/run/docker.sock"
                            },
                            {
                                "SourceVolume": "jenkins_home",
                                "ContainerPath": "/var/jenkins_home"
                            }
                        ]
                    }


                ],
                "Volumes": [
                    {
                        "Name": "jenkins_home",
                        "Host": { "SourcePath": "/ecs/jenkins_home" }
                    },
                    {
                        "Name": "docker",
                        "Host": { "SourcePath": "/var/run/docker.sock" }
                    }
                ]
            }
        },
        "EcsService": {
            "Type": "AWS::ECS::Service",
            "Properties": {
                "Cluster": { "Ref": "EcsCluster" },
                "TaskDefinition": { "Ref": "EcsTaskDefinition" },
                "DesiredCount": 1
            }
        }
    },
    "Outputs":{
        "ElbDomainName": {
            "Description": "Public DNS name of Elastic Load Balancer",
            "Value": {
                "Fn::GetAtt": [
                    "ElasticLoadBalancer",
                    "DNSName"
                ]
            }
        },
        "EC2InstanceDomainName": {
            "Description": "Public DNS name of EC2 instance",
            "Value": {
                "Fn::GetAtt": [
                    "EC2Instance",
                    "PublicDnsName"
                ]
            }
        }
    }
}

jenkins master() 的 docker 文件在哪里jenkins:ecs

FROM jenkins/jenkins:2.190.2

MAINTAINER Developer team <devteam@abc.com>

# Suppress apt installation warnings
# https://serverfault.com/a/227194/220043
ENV DEBIAN_FRONTEND=noninteractive

# Official Jenkins image does not include sudo, change to root user
USER root

# Used to set the docker group ID
# Set to 497 by default, which is the groupID used by AWS Linux ECS instance
ARG DOCKER_GID=497

# Create Docker Group with GID
# Set default value of 497 if DOCKER_GID set to blank string by Docker compose
RUN groupadd -g ${DOCKER_GID:-497} docker

# Install base packages for docker, docker-compose & ansible
# apt-key adv --keyserver keyserver.ubuntu.com --recv-keys AA8E81B4331F7F50 && \
RUN apt-get update -y && \
    apt-get -y install bc \
                    gawk \
                    libffi-dev \
                    musl-dev \
                    apt-transport-https \
                    curl \
                    python3 \
                    python3-dev \
                    python3-setuptools \
                    gcc \
                    make \
                    libssl-dev \
                    python3-pip 

# Used at build time but not runtime
ARG DOCKER_VERSION=18.06.1~ce~3-0~debian

# Install the latest Docker CE binaries and add user `jenkins` to the docker group
RUN apt-get update && \
    apt-get -y install apt-transport-https \
    ca-certificates \
    curl \
    gnupg-agent \
    software-properties-common && \
    curl -fsSL https://download.docker.com/linux/$(. /etc/os-release; echo "$ID")/gpg > /tmp/dkey; apt-key add /tmp/dkey && \
    add-apt-repository \
      "deb [arch=amd64] https://download.docker.com/linux/$(. /etc/os-release; echo "$ID") \
      $(lsb_release -cs) \
      stable" && \
    apt-get update && \
    apt-get -y install docker-ce=${DOCKER_VERSION:-18.06.1~ce~3-0~debian}  && \
        # docker-ce-cli=${DOCKER_VERSION:-18.06.1~ce~3-0~debian} \
        # containerd.io && \
    usermod -aG docker jenkins

ARG DOCKER_COMPOSE=1.24.1

# Install docker compose
RUN curl -L "https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE:-1.24.1}/docker-compose-$(uname -s)-$(uname -m)" \
    -o /usr/local/bin/docker-compose && \
    chmod +x /usr/local/bin/docker-compose && \
    pip3 install ansible boto3

# Change to jenkins user
USER jenkins

# Add jenkins plugin
COPY plugins.txt /usr/share/jenkins/plugins.txt
RUN /usr/local/bin/install-plugins.sh < /usr/share/jenkins/plugins.txt

主 jenkins docker 容器在 EC2(docker 主机)中运行。

在这种情况下,ELB 不用于负载均衡,而是用于公开面对 Jenkins。当前 ELB 使用http


如何https通过 ELB 启用与詹金斯的安全连接?

哪个组件负责确保安全连接?ELB 或詹金斯

标签: amazon-web-servicesssljenkinshttpsdockerfile

解决方案


尝试使用 AWS ACM 在 ELB 上设置 SSL 证书。完成后,在 ELB 上为 https 创建一个安全侦听器,并使用下面提到的步骤将该流量转发到 Jenkins 的 http 端口:

AWS ACM

  • 导航到 AWS ACM 并单击“请求证书”按钮。
  • 选择“请求公共证书”选项
  • 添加需要证书的域名
  • 选择“DNS 验证”进行证书验证
  • 添加标签(可选)并查看并确认
  • 如果您将 AWS route53 用于您的 DNS,那么有一个按钮可以自动为您在 route53 中的证书创建 CNAME 条目。如果您使用任何其他 DNS,请确保按照 ACM 所述创建 CNAME 记录。
  • 在 DNS 上验证 CNAME 记录后,您的 ACM 证书状态将从“待处理”变为“已颁发”

AWS ELB - 经典负载均衡器

  • 使用下面提到的详细信息向负载均衡器添加一个新的侦听器:

    • 负载均衡器协议:HTTPS(安全 HTTP)

    • 负载均衡器端口:443

    • 实例协议:HTTP

    • 实例端口:8080(或您已配置 Jenkins 的任何其他端口)

AWS ELB - 应用程序负载均衡器

  • 如果您使用 ALB,则创建一个目标组,其目标类型为:实例,协议:HTTP,端口:8080

如果您在运行状况检查中遇到任何问题,请确保您的安全组允许来自 ELB/ALB 的端口 8080 上的流量。

另一种方法是在服务器上安装 nginx 并使用下面列出的服务器文件配置(在这种情况下,将上述 ELB/ALB 配置中的 8080 更改为 80):

server {
    listen 80;

    server_name xxx.xxx.xxx;

    location / {
        proxy_pass http://localhost:8080;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
}

https://docs.aws.amazon.com/acm/latest/userguide/gs-acm-request-public.html https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/elb-listener-config .html https://docs.aws.amazon.com/elasticloadbalancing/latest/application/create-https-listener.html


推荐阅读