├── .github └── workflows │ └── ci-go.yml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── SUMMARY.md ├── deployments ├── CRD │ ├── KubeArmorExternalWorkload.yaml │ ├── KubeArmorExternalWorkloadPolicy.yaml │ └── KubeArmorHostPolicy.yaml └── etcd.yml ├── examples ├── ew-demo-01.sh ├── ewkhp.yaml ├── kew2policy.yaml ├── kewpolicy.yaml └── khp.yaml ├── getting-started ├── GKE │ ├── README.md │ ├── etcd.yml │ └── kvmsoperator.yaml ├── kvmservice-nonk8s.md ├── minikube │ ├── README.md │ ├── install_minikube.sh │ ├── kvmservice.yaml │ └── kvmsoperator.yaml └── res │ ├── kvmservice-k8s-control-plane.png │ └── kvmservice-non-k8s-control-plane.png ├── helm └── templates │ ├── security.kubearmor.com_kubearmorexternalworkload.yaml │ ├── security.kubearmor.com_kubearmorexternalworkloads.yaml │ └── security.kubearmor.com_kubearmorhostpolicies.yaml ├── pkg ├── KubeArmorExternalWorkload │ ├── Makefile │ ├── PROJECT │ ├── api │ │ └── v1 │ │ │ ├── groupversion_info.go │ │ │ ├── kubearmorexternalworkload_types.go │ │ │ └── zz_generated.deepcopy.go │ ├── bin │ │ └── manager │ ├── config │ │ ├── crd │ │ │ ├── bases │ │ │ │ ├── security.kubearmor.com_kubearmorexternalworkload.yaml │ │ │ │ └── security.kubearmor.com_kubearmorexternalworkloads.yaml │ │ │ ├── kustomization.yaml │ │ │ └── kustomizeconfig.yaml │ │ ├── default │ │ │ ├── kustomization.yaml │ │ │ └── manager.yaml │ │ ├── manager │ │ │ ├── kustomization.yaml │ │ │ └── manager.yaml │ │ └── rbac │ │ │ └── role.yaml │ ├── controllers │ │ ├── kubearmorexternalworkload_controller.go │ │ └── suite_test.go │ ├── go.mod │ ├── go.sum │ ├── hack │ │ └── boilerplate.go.txt │ ├── kustomize │ └── main.go └── KubeArmorHostPolicy │ ├── .gitignore │ ├── Dockerfile │ ├── Makefile │ ├── PROJECT │ ├── api │ └── v1 │ │ ├── groupversion_info.go │ │ ├── kubearmorhostpolicy_types.go │ │ └── zz_generated.deepcopy.go │ ├── config │ ├── certmanager │ │ ├── certificate.yaml │ │ ├── kustomization.yaml │ │ └── kustomizeconfig.yaml │ ├── crd │ │ ├── bases │ │ │ └── security.kubearmor.com_kubearmorhostpolicies.yaml │ │ ├── kustomization.yaml │ │ ├── kustomizeconfig.yaml │ │ └── patches │ │ │ ├── cainjection_in_kubearmorhostpolicies.yaml │ │ │ └── webhook_in_kubearmorhostpolicies.yaml │ ├── default │ │ ├── kustomization.yaml │ │ ├── manager_auth_proxy_patch.yaml │ │ ├── manager_webhook_patch.yaml │ │ └── webhookcainjection_patch.yaml │ ├── manager │ │ ├── kustomization.yaml │ │ └── manager.yaml │ ├── prometheus │ │ ├── kustomization.yaml │ │ └── monitor.yaml │ ├── rbac │ │ ├── auth_proxy_client_clusterrole.yaml │ │ ├── auth_proxy_role.yaml │ │ ├── auth_proxy_role_binding.yaml │ │ ├── auth_proxy_service.yaml │ │ ├── kubearmorhostpolicy_editor_role.yaml │ │ ├── kubearmorhostpolicy_viewer_role.yaml │ │ ├── kustomization.yaml │ │ ├── leader_election_role.yaml │ │ ├── leader_election_role_binding.yaml │ │ ├── role.yaml │ │ └── role_binding.yaml │ ├── samples │ │ └── security_v1_kubearmorhostpolicy.yaml │ └── webhook │ │ ├── kustomization.yaml │ │ ├── kustomizeconfig.yaml │ │ └── service.yaml │ ├── controllers │ ├── kubearmorhostpolicy_controller.go │ └── suite_test.go │ ├── go.mod │ ├── go.sum │ ├── hack │ └── boilerplate.go.txt │ └── main.go ├── scripts ├── install-workload.sh ├── operator.sh └── service.sh ├── setup.sh └── src ├── common ├── common.go ├── go.mod └── go.sum ├── constants ├── constants.go └── go.mod ├── etcd ├── etcdClient.go ├── go.mod └── go.sum ├── log ├── go.mod ├── go.sum └── logger.go ├── operator ├── Makefile ├── build │ ├── Dockerfile.kvmsoperator │ ├── Makefile │ ├── build_kvmoperator.sh │ ├── clean_source_files.sh │ ├── copy_source_files.sh │ ├── patch.sh │ └── patch_selinux.sh ├── core │ ├── crdHandler.go │ ├── k8sHandler.go │ └── kvmOperator.go ├── go.mod ├── go.sum ├── kvmsoperator.yaml └── main.go ├── service ├── Makefile ├── build │ ├── Dockerfile.kvmservice │ ├── Makefile │ ├── build_kvmservice.sh │ ├── clean_source_files.sh │ ├── copy_source_files.sh │ ├── patch.sh │ └── patch_selinux.sh ├── core │ ├── go.mod │ ├── go.sum │ ├── k8sHandler.go │ ├── kvmService.go │ └── kvmsUpdate.go ├── genscript │ ├── genscript.go │ ├── go.mod │ └── go.sum ├── go.mod ├── go.sum ├── kvmservice.yaml ├── main.go ├── patch.sh ├── protobuf │ ├── Makefile │ ├── clihandler.pb.go │ ├── clihandler.proto │ ├── go.mod │ ├── go.sum │ ├── kvm.pb.go │ └── kvm.proto └── server │ ├── clihandler.go │ ├── go.mod │ ├── go.sum │ ├── kvmserver.go │ └── server.go └── types ├── go.mod ├── go.sum └── types.go /.github/workflows/ci-go.yml: -------------------------------------------------------------------------------- 1 | name: ci-go 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - dev 8 | pull_request: 9 | branches: 10 | - main 11 | - dev 12 | 13 | jobs: 14 | go-fmt: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: Checkout Source 18 | uses: actions/checkout@v2 19 | 20 | - uses: actions/setup-go@v2 21 | with: 22 | go-version: v1.17 23 | 24 | - name: Check gofmt 25 | run: make -C src/service gofmt 26 | 27 | go-sec: 28 | runs-on: ubuntu-latest 29 | steps: 30 | - name: Checkout Source 31 | uses: actions/checkout@v2 32 | 33 | - uses: actions/setup-go@v2 34 | with: 35 | go-version: v1.17 36 | 37 | - name: Run Gosec Security Scanner 38 | run: make -C src/service gosec 39 | 40 | go-lint: 41 | runs-on: ubuntu-latest 42 | steps: 43 | - name: Checkout Source 44 | uses: actions/checkout@v2 45 | 46 | - name: golangci-lint 47 | with: 48 | working-directory: src/service 49 | args: --timeout=300s 50 | uses: golangci/golangci-lint-action@v2 51 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | service/kvmservice 2 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Community Code of Conduct v1.0 2 | 3 | This is Code of Conduct is based on the [CNCF Code of 4 | Conduct](https://github.com/cncf/foundation/edit/master/code-of-conduct.md). 5 | See the referred document for translated versions into different languages. The 6 | text below is modified with KubeArmor community specific contact details. 7 | 8 | ### Contributor Code of Conduct 9 | 10 | As contributors and maintainers of this project, and in the interest of fostering 11 | an open and welcoming community, we pledge to respect all people who contribute 12 | through reporting issues, posting feature requests, updating documentation, 13 | submitting pull requests or patches, and other activities. 14 | 15 | We are committed to making participation in this project a harassment-free experience for 16 | everyone, regardless of level of experience, gender, gender identity and expression, 17 | sexual orientation, disability, personal appearance, body size, race, ethnicity, age, 18 | religion, or nationality. 19 | 20 | Examples of unacceptable behavior by participants include: 21 | 22 | * The use of sexualized language or imagery 23 | * Personal attacks 24 | * Trolling or insulting/derogatory comments 25 | * Public or private harassment 26 | * Publishing others' private information, such as physical or electronic addresses, 27 | without explicit permission 28 | * Other unethical or unprofessional conduct. 29 | 30 | Project maintainers have the right and responsibility to remove, edit, or reject 31 | comments, commits, code, wiki edits, issues, and other contributions that are not 32 | aligned to this Code of Conduct. By adopting this Code of Conduct, project maintainers 33 | commit themselves to fairly and consistently applying these principles to every aspect 34 | of managing this project. Project maintainers who do not follow or enforce the Code of 35 | Conduct may be permanently removed from the project team. 36 | 37 | This code of conduct applies both within project spaces and in public spaces 38 | when an individual is representing the project or its community. 39 | 40 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 41 | reported by contacting the project maintainers or our mediator, Nandhini Ananthakalyanaraman 42 | . 43 | 44 | This Code of Conduct is adapted from the Contributor Covenant 45 | (http://contributor-covenant.org), version 1.2.0, available at 46 | http://contributor-covenant.org/version/1/2/0/ 47 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to Contribute to KubeArmor VM Service (kvmservice)? 2 | 3 | Thank you for your interest in contributing to KubeArmor VM Service (kvmservice)! Your contributions can help enhance this project and benefit the wider community. Here's how you can get involved: 4 | 5 | ## Finding an Issue to Work On 6 | 7 | 1. Check out the [issue tracker](https://github.com/kubearmor/kvm-service/issues) to find issues that match your skills and interests. 8 | 9 | 2. If you're new to the project, consider looking for issues labeled as [good-first-issue](https://github.com/kubearmor/kvm-service/labels/good%20first%20issue) for a beginner-friendly start. 10 | 11 | 3. Experienced contributors can take on more challenging tasks by selecting issues labeled as [help-wanted](https://github.com/kubearmor/kvm-service/labels/help%20wanted). 12 | 13 | ## Contributing Code 14 | 15 | 1. Fork the repository and create a new branch for your contribution. 16 | 17 | 2. Implement your changes and improvements. 18 | 19 | 3. Follow the project's coding style and conventions. 20 | 21 | 4. Ensure your code is well-tested and doesn't introduce any regressions. 22 | 23 | 5. Submit a pull request to the main repository. Provide a clear description of your changes and why they are valuable. 24 | 25 | ## Scope of Contribution 26 | 27 | Contributions to kvmservice go beyond code. You can also contribute in the following ways: 28 | 29 | 1. **Documentation**: Improve existing documentation or add new sections to make it easier for users and contributors to understand and use kvmservice. 30 | 31 | 2. **Testing and Bug Reports**: Help identify and report bugs, as well as test fixes and improvements to ensure a stable and reliable project. 32 | 33 | 3. **Feature Ideas**: Share your ideas for new features or enhancements that can add value to kvmservice. 34 | 35 | 4. **Community Engagement**: Participate in discussions, provide feedback, and assist other contributors on the [KubeArmor Slack](https://kubearmor.slack.com/) and other community channels. 36 | 37 | ## Code of Conduct 38 | 39 | When contributing to kvmservice, please adhere to our [Code of Conduct](./CODE_OF_CONDUCT.md). We aim to create a welcoming and inclusive environment for all contributors. 40 | 41 | ## Get Involved 42 | 43 | Your contributions are vital to the success of KubeArmor VM Service (kvmservice). Thank you for being part of our community and helping us make kvmservice even better! 44 | 45 | For more information, you can visit our [project's homepage](https://github.com/kubearmor/kvm-service) and [KubeArmor Wiki](https://github.com/kubearmor/KubeArmor/wiki). 46 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # KubeArmor VM Service (kvmservice) 2 | 3 | ## Introduction 4 | 5 | Kubearmor Virtual Machine Service allows orchestrating policies to VMs and Bare-Metal environments using either k8s or non-k8s control plane. 6 | kvmservice can either run as: 7 | 1. k8s service + operator in k8s based control plane 8 | 2. directly on VM/Bare-metal as systemd process 9 | 10 | ### Use-cases/Requirements 11 | - [x] Onboard kubearmor/cilium to virtual machines/bare-metals/edge-devices 12 | - [x] Orchestrate kubearmor and cilium policies to VMs 13 | - [x] Handle observability in a unified manner 14 | - [x] Support hybrid deployments of k8s and Virtual machines based workloads. 15 | - [x] Support automated policy discovery for kubearmor/cilium for VMs 16 | 17 | > Note: Virtual Machines, Bare-Metal machines, Edge Devices can be used interchangeably in this document. 18 | 19 | ## High Level Arch for Hybrid Deployment 20 | 21 | A deployment might have workloads distributed across both k8s and non-k8s (VM-based) environments. The primary aim is to support kubearmor/cilium onboarding, policy orchestration, observability across these environments using the same toolsets. This allows simplified management of workloads for organizations who are in the midst of migrating to k8s from VMs or for those who might rely on VMs for a forseable future. 22 | 23 | ![](./getting-started/res/kvmservice-k8s-control-plane.png) 24 | 25 | ## High Level Arch for VM-only deployments 26 | 27 | There are organizations who might not support k8s for forseable future and their workloads will primarily be on cloud VMs or their own data-center VMs or even bare-metal machines. kvmservice allows onboarding, policy orchestration, observability for such environments. 28 | 29 | ![](./getting-started/res/kvmservice-non-k8s-control-plane.png) 30 | 31 | ## Additional Documents 32 | 33 | * [Deploying KubeArmor at scale on VMs using non-k8s control plane](./getting-started/kvmservice-nonk8s.md) 34 | * [Google Slides for initial design discussions](https://docs.google.com/presentation/d/1aa0fVLWHcVkaGbb70Jy6dek7KOYIAailx3and-mjh8M/edit?usp=sharing) 35 | 36 | 37 | -------------------------------------------------------------------------------- /SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Table of contents 2 | 3 | * [KubeArmor KVM Service](README.md) 4 | 5 | ## Getting Started 6 | 7 | ## Contribution 8 | 9 | 10 | ## Reference 11 | 12 | 13 | ## Examples 14 | 15 | -------------------------------------------------------------------------------- /deployments/CRD/KubeArmorExternalWorkload.yaml: -------------------------------------------------------------------------------- 1 | 2 | --- 3 | apiVersion: apiextensions.k8s.io/v1 4 | kind: CustomResourceDefinition 5 | metadata: 6 | annotations: 7 | controller-gen.kubebuilder.io/version: v0.2.5 8 | creationTimestamp: null 9 | name: kubearmorexternalworkloads.security.kubearmor.com 10 | spec: 11 | group: security.kubearmor.com 12 | names: 13 | kind: KubeArmorExternalWorkload 14 | listKind: KubeArmorExternalWorkloadList 15 | plural: kubearmorexternalworkloads 16 | shortNames: 17 | - kew 18 | singular: kubearmorexternalworkload 19 | scope: Cluster 20 | versions: 21 | - name: v1 22 | schema: 23 | openAPIV3Schema: 24 | properties: 25 | apiVersion: 26 | description: 'APIVersion defines the versioned schema of this representation 27 | of an object. Servers should convert recognized schemas to the latest 28 | internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' 29 | type: string 30 | kind: 31 | description: 'Kind is a string value representing the REST resource this 32 | object represents. Servers may infer this from the endpoint the client 33 | submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' 34 | type: string 35 | metadata: 36 | type: object 37 | status: 38 | description: Status is the most recent status of the external KubeArmor 39 | workload. It is a read-only field. 40 | properties: 41 | id: 42 | description: ID is the numeric identity allocated for the external 43 | workload. 44 | format: int64 45 | type: integer 46 | ip: 47 | description: IP is the IP address of the workload. Empty if the workload 48 | has not registered. 49 | type: string 50 | type: object 51 | required: 52 | - metadata 53 | type: object 54 | served: true 55 | storage: true 56 | subresources: 57 | status: {} 58 | status: 59 | acceptedNames: 60 | kind: "" 61 | plural: "" 62 | conditions: [] 63 | storedVersions: [] 64 | -------------------------------------------------------------------------------- /deployments/CRD/KubeArmorExternalWorkloadPolicy.yaml: -------------------------------------------------------------------------------- 1 | 2 | --- 3 | apiVersion: apiextensions.k8s.io/v1 4 | kind: CustomResourceDefinition 5 | metadata: 6 | annotations: 7 | controller-gen.kubebuilder.io/version: v0.2.5 8 | creationTimestamp: null 9 | name: kubearmorexternalworkloads.security.kubearmor.com 10 | spec: 11 | group: security.kubearmor.com 12 | names: 13 | kind: KubeArmorExternalWorkload 14 | listKind: KubeArmorExternalWorkloadList 15 | plural: kubearmorexternalworkloads 16 | shortNames: 17 | - kew 18 | singular: kubearmorexternalworkload 19 | scope: Cluster 20 | versions: 21 | - name: v1 22 | schema: 23 | openAPIV3Schema: 24 | properties: 25 | apiVersion: 26 | description: 'APIVersion defines the versioned schema of this representation 27 | of an object. Servers should convert recognized schemas to the latest 28 | internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' 29 | type: string 30 | kind: 31 | description: 'Kind is a string value representing the REST resource this 32 | object represents. Servers may infer this from the endpoint the client 33 | submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' 34 | type: string 35 | metadata: 36 | type: object 37 | status: 38 | description: Status is the most recent status of the external KubeArmor 39 | workload. It is a read-only field. 40 | properties: 41 | id: 42 | description: ID is the numeric identity allocated for the external 43 | workload. 44 | format: int64 45 | type: integer 46 | ip: 47 | description: IP is the IP address of the workload. Empty if the workload 48 | has not registered. 49 | type: string 50 | type: object 51 | required: 52 | - metadata 53 | type: object 54 | served: true 55 | storage: true 56 | subresources: 57 | status: {} 58 | status: 59 | acceptedNames: 60 | kind: "" 61 | plural: "" 62 | conditions: [] 63 | storedVersions: [] 64 | -------------------------------------------------------------------------------- /deployments/etcd.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: etcd-client 5 | namespace: kube-system 6 | spec: 7 | ports: 8 | - name: etcd-client-port 9 | port: 2379 10 | protocol: TCP 11 | targetPort: 2379 12 | selector: 13 | app: etcd 14 | 15 | --- 16 | 17 | apiVersion: v1 18 | kind: Pod 19 | metadata: 20 | labels: 21 | app: etcd 22 | etcd_node: etcd0 23 | name: etcd0 24 | namespace: kube-system 25 | spec: 26 | containers: 27 | - command: 28 | - /usr/local/bin/etcd 29 | - --name 30 | - etcd0 31 | - --initial-advertise-peer-urls 32 | - http://etcd0:2380 33 | - --listen-peer-urls 34 | - http://0.0.0.0:2380 35 | - --listen-client-urls 36 | - http://0.0.0.0:2379 37 | - --advertise-client-urls 38 | - http://etcd0:2379 39 | - --initial-cluster 40 | - etcd0=http://etcd0:2380 41 | - --initial-cluster-state 42 | - new 43 | - --client-cert-auth=false 44 | - --auto-tls=false 45 | image: quay.io/coreos/etcd:latest 46 | name: etcd0 47 | securityContext: 48 | privileged: true 49 | ports: 50 | - containerPort: 2379 51 | name: client 52 | protocol: TCP 53 | - containerPort: 2380 54 | name: server 55 | protocol: TCP 56 | restartPolicy: Always 57 | volumes: 58 | - name: etc-kubernetes-certs 59 | hostPath: 60 | path: /etc/kubernetes/pki/etcd/ 61 | type: DirectoryOrCreate 62 | 63 | --- 64 | 65 | apiVersion: v1 66 | kind: Service 67 | metadata: 68 | labels: 69 | etcd_node: etcd0 70 | name: etcd0 71 | namespace: kube-system 72 | spec: 73 | ports: 74 | - name: client 75 | port: 2379 76 | protocol: TCP 77 | targetPort: 2379 78 | - name: server 79 | port: 2380 80 | protocol: TCP 81 | targetPort: 2380 82 | selector: 83 | etcd_node: etcd0 84 | -------------------------------------------------------------------------------- /examples/ew-demo-01.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | set -x 4 | shopt -s extglob 5 | 6 | if [ -z "$CLUSTER_ADDR" ] ; then 7 | echo "CLUSTER_ADDR must be defined to the IP:PORT at which the KVM Service is reachable." 8 | exit 1 9 | fi 10 | 11 | port='@(6553[0-5]|655[0-2][0-9]|65[0-4][0-9][0-9]|6[0-4][0-9][0-9][0-9]|[1-5][0-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9]|[1-9])' 12 | byte='@(25[0-5]|2[0-4][0-9]|[1][0-9][0-9]|[1-9][0-9]|[0-9])' 13 | ipv4="$byte\.$byte\.$byte\.$byte" 14 | 15 | # Default port is for a HostPort service 16 | case "$CLUSTER_ADDR" in 17 | \[+([0-9a-fA-F:])\]:$port) 18 | CLUSTER_PORT=${CLUSTER_ADDR##\[*\]:} 19 | CLUSTER_IP=${CLUSTER_ADDR#\[} 20 | CLUSTER_IP=${CLUSTER_IP%\]:*} 21 | ;; 22 | [^[]$ipv4:$port) 23 | CLUSTER_PORT=${CLUSTER_ADDR##*:} 24 | CLUSTER_IP=${CLUSTER_ADDR%:*} 25 | ;; 26 | *:*) 27 | echo "Malformed CLUSTER_ADDR: $CLUSTER_ADDR" 28 | exit 1 29 | ;; 30 | *) 31 | CLUSTER_PORT=12345 32 | CLUSTER_IP=$CLUSTER_ADDR 33 | ;; 34 | esac 35 | 36 | export EXTERNAL_WORKLOAD=1234 37 | 38 | DOCKER_OPTS=" -d -p 32767:32767 --log-driver syslog --restart always" 39 | DOCKER_OPTS+=" --privileged --add-host kvms.kubearmor.io:$CLUSTER_IP" 40 | DOCKER_OPTS+=" --volume /var/run/docker.sock:/var/run/docker.sock" 41 | DOCKER_OPTS+=" --volume /usr/src:/usr/src" 42 | DOCKER_OPTS+=" --volume /lib/modules:/lib/modules" 43 | DOCKER_OPTS+=" --volume /sys/fs/bpf:/sys/fs/bpf" 44 | DOCKER_OPTS+=" --volume /sys/kernel/debug:/sys/kernel/debug" 45 | DOCKER_OPTS+=" --volume /etc/apparmor.d:/etc/apparmor.d" 46 | DOCKER_OPTS+=" --volume /etc/os-release:/media/root/etc/os-release" 47 | 48 | KUBEARMOR_OPTS="-gRPC=32767 -logPath=/tmp/kubearmor.log -enableKubeArmorHostPolicy" 49 | 50 | if [ -n "$(sudo docker ps -a -q -f name=kubearmor)" ]; then 51 | echo "Shutting down running kubearmor agent" 52 | sudo docker rm -f kubearmor || true 53 | fi 54 | 55 | KUBEARMOR_IMAGE="kubearmor/kubearmor:latest" 56 | 57 | echo "Launching kubearmor agent..." 58 | sudo docker run --name kubearmor $DOCKER_OPTS $KUBEARMOR_IMAGE kubearmor $KUBEARMOR_OPTS 59 | 60 | -------------------------------------------------------------------------------- /examples/ewkhp.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: security.kubearmor.com/v1 2 | kind: KubeArmorHostPolicy 3 | metadata: 4 | name: ew-khp-01 5 | spec: 6 | nodeSelector: 7 | matchLabels: 8 | abc: xyz 9 | severity: 5 10 | file: 11 | matchPaths: 12 | - path: /proc/cpuinfo # cat /etc/passwd 13 | action: 14 | Block 15 | -------------------------------------------------------------------------------- /examples/kew2policy.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: security.kubearmor.com/v1 2 | kind: KubeArmorExternalWorkloadPolicy 3 | metadata: 4 | name: demo-kew-02 5 | labels: 6 | abc: xyz 7 | #io.kubernetes.pod.namespace: default 8 | -------------------------------------------------------------------------------- /examples/kewpolicy.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: security.kubearmor.com/v1 2 | kind: KubeArmorExternalWorkload 3 | metadata: 4 | name: kvm1 5 | labels: 6 | abc: xyz 7 | #io.kubernetes.pod.namespace: default 8 | -------------------------------------------------------------------------------- /examples/khp.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: security.kubearmor.com/v1 2 | kind: KubeArmorHostPolicy 3 | metadata: 4 | name: hsp-kubearmor-dev-file-path-audit 5 | spec: 6 | nodeSelector: 7 | matchLabels: 8 | kubernetes.io/hostname: kubearmor-dev 9 | severity: 5 10 | file: 11 | matchPaths: 12 | - path: /etc/passwd # cat /etc/passwd 13 | action: 14 | Audit 15 | -------------------------------------------------------------------------------- /getting-started/GKE/README.md: -------------------------------------------------------------------------------- 1 | # Steps for launching kvmsoperator in any GKE cluster 2 | Follow the steps mentioned below to install/deploy kvmsoperator on any GKE cluster. 3 | Connect to any GKE cluster of your choice. 4 | 5 | Once connected, follow the instructions below. 6 | 7 | ## Deploying our own etcd. 8 | GKE has it own etcd and also manages the same in its control pane. 9 | The pods in control pane are not visible outside. 10 | 11 | For kvmsoperator to be deployed, we require etcd to be up and running and also the etcd service's IP visible. 12 | Since we do not have access to that information, we will be deploying our own etcd. 13 | 14 | ### Deploy ETCD 15 | Deploy etcd using below commands. 16 | 17 | ``` 18 | $ kubectl apply -f etcd.yml 19 | service/etcd-client created 20 | pod/etcd0 created 21 | service/etcd0 created 22 | $ 23 | ``` 24 | Once etcd is deployed, get the clusterIP of the deployed etcd service using below command. 25 | 26 | ``` 27 | $ kubectl get services -A 28 | NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE 29 | default kubernetes ClusterIP 10.92.0.1 443/TCP 5d22h 30 | kube-system default-http-backend NodePort 10.92.0.215 80:31820/TCP 5d22h 31 | kube-system etcd-client ClusterIP 10.92.11.42 2379/TCP 71s 32 | kube-system etcd0 ClusterIP 10.92.14.153 2379/TCP,2380/TCP 69s 33 | kube-system kube-dns ClusterIP 10.92.0.10 53/UDP,53/TCP 5d22h 34 | kube-system kubearmor ClusterIP 10.92.7.176 32767/TCP 50m 35 | kube-system kubearmor-host-policy-manager-metrics-service ClusterIP 10.92.0.251 8443/TCP 50m 36 | kube-system kubearmor-policy-manager-metrics-service ClusterIP 10.92.1.107 8443/TCP 50m 37 | kube-system kvmsoperator-59df4c8897-m7sx2-jqrsm ClusterIP 10.92.5.66 32770/TCP 2d23h 38 | kube-system metrics-server ClusterIP 10.92.6.70 443/TCP 5d22h 39 | $ 40 | 41 | ``` 42 | Make a note of the etcd0 cluster IP. Here the etcd cluster IP is 10.92.14.153 43 | This IP is required to be configured in kvmsoperator. 44 | 45 | ## Deploy kvmsoperator service 46 | Before deploying kvmsoperator, 2 things to be noted down. 47 | 1. The IP of the connected GKE cluster. 48 | 2. The cluster IP of the running etcd0 service. 49 | 50 | ### kvmsoperator operator yaml modifications 51 | 1. In line 66, replace the IP with the GKE cluster IP. 52 | 2. In line 69, replace the IP with the etcd0 service's cluster IP. 53 | 54 | Once the above modifications are complete, deploy kvmsoperator with below commands. 55 | 56 | ``` 57 | $ kubectl apply -f kvmsoperator.yaml 58 | serviceaccount/kvmsoperator created 59 | clusterrolebinding.rbac.authorization.k8s.io/kvmsoperator created 60 | service/kvmsoperator created 61 | deployment.apps/kvmsoperator created 62 | $ 63 | ``` 64 | 65 | kvmsoperator is deployed. To check the logs of kvmsoperator, run below command 66 | 67 | ``` 68 | $ kubectl logs -n kube-system kvmsoperator-68c4bccdd4-6mzlw 69 | 2021-11-01 06:17:47.509570 INFO ENTRY! 70 | 2021-11-01 06:17:47.510076 INFO Getting lease 71 | 2021-11-01 06:17:47.518585 INFO Initialized the ETCD client! 72 | 2021-11-01 06:17:47.518659 INFO Initiliazing the CLIHandler => Port:32770 73 | 2021-11-01 06:17:47.518738 INFO Successfully initialized the KVMSOperator with args => (clusterIp:'35.238.22.7' clusterPort:40400 74 | 2021-11-01 06:17:48.521887 INFO Started the external workload CRD watcher 75 | 2021-11-01 06:17:48.521964 INFO Started the CLI Handler 76 | 2021-11-01 06:17:48.523054 INFO Successfully CLIHandler Listening on port 32770 77 | $ 78 | ``` 79 | 80 | kvmsoperator is successfuly deployed and running. -------------------------------------------------------------------------------- /getting-started/GKE/etcd.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: etcd-client 5 | namespace: kube-system 6 | spec: 7 | ports: 8 | - name: etcd-client-port 9 | port: 2379 10 | protocol: TCP 11 | targetPort: 2379 12 | selector: 13 | app: etcd 14 | 15 | --- 16 | 17 | apiVersion: v1 18 | kind: Pod 19 | metadata: 20 | labels: 21 | app: etcd 22 | etcd_node: etcd0 23 | name: etcd0 24 | namespace: kube-system 25 | spec: 26 | containers: 27 | - command: 28 | - /usr/local/bin/etcd 29 | - --name 30 | - etcd0 31 | - --initial-advertise-peer-urls 32 | - http://etcd0:2380 33 | - --listen-peer-urls 34 | - http://0.0.0.0:2380 35 | - --listen-client-urls 36 | - http://0.0.0.0:2379 37 | - --advertise-client-urls 38 | - http://etcd0:2379 39 | - --initial-cluster 40 | - etcd0=http://etcd0:2380 41 | - --initial-cluster-state 42 | - new 43 | - --client-cert-auth=false 44 | - --auto-tls=false 45 | image: quay.io/coreos/etcd:latest 46 | name: etcd0 47 | securityContext: 48 | privileged: true 49 | ports: 50 | - containerPort: 2379 51 | name: client 52 | protocol: TCP 53 | - containerPort: 2380 54 | name: server 55 | protocol: TCP 56 | restartPolicy: Always 57 | volumes: 58 | - name: etc-kubernetes-certs 59 | hostPath: 60 | path: /etc/kubernetes/pki/etcd/ 61 | type: DirectoryOrCreate 62 | 63 | --- 64 | 65 | apiVersion: v1 66 | kind: Service 67 | metadata: 68 | labels: 69 | etcd_node: etcd0 70 | name: etcd0 71 | namespace: kube-system 72 | spec: 73 | ports: 74 | - name: client 75 | port: 2379 76 | protocol: TCP 77 | targetPort: 2379 78 | - name: server 79 | port: 2380 80 | protocol: TCP 81 | targetPort: 2380 82 | selector: 83 | etcd_node: etcd0 84 | -------------------------------------------------------------------------------- /getting-started/GKE/kvmsoperator.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: kvmsoperator 5 | namespace: kube-system 6 | --- 7 | apiVersion: rbac.authorization.k8s.io/v1 8 | kind: ClusterRoleBinding 9 | metadata: 10 | name: kvmsoperator 11 | roleRef: 12 | apiGroup: rbac.authorization.k8s.io 13 | kind: ClusterRole 14 | name: cluster-admin 15 | subjects: 16 | - kind: ServiceAccount 17 | name: kvmsoperator 18 | namespace: kube-system 19 | --- 20 | apiVersion: v1 21 | kind: Service 22 | metadata: 23 | name: kvmsoperator 24 | namespace: kube-system 25 | spec: 26 | selector: 27 | kvmsoperator-app: kvmsoperator 28 | ports: 29 | - port: 32770 30 | protocol: TCP 31 | targetPort: 32770 32 | --- 33 | apiVersion: apps/v1 34 | kind: Deployment 35 | metadata: 36 | name: kvmsoperator 37 | namespace: kube-system 38 | labels: 39 | kvmsoperator-app: kvmsoperator 40 | spec: 41 | selector: 42 | matchLabels: 43 | kvmsoperator-app: kvmsoperator 44 | template: 45 | metadata: 46 | labels: 47 | kvmsoperator-app: kvmsoperator 48 | annotations: 49 | container.apparmor.security.beta.kubernetes.io/kvmsoperator: unconfined 50 | spec: 51 | serviceAccountName: kvmsoperator 52 | nodeSelector: 53 | kubernetes.io/os: linux 54 | tolerations: 55 | - operator: Exists 56 | hostPID: true 57 | hostNetwork: true 58 | restartPolicy: Always 59 | dnsPolicy: ClusterFirstWithHostNet 60 | containers: 61 | - name: kvmsoperator 62 | image: seswarrajan/kvmsoperator:latest 63 | imagePullPolicy: Always 64 | securityContext: 65 | privileged: true 66 | args: ["-port=40400", "-ipAddress='35.238.22.7'"] 67 | env: 68 | - name: ENDPOINTS 69 | value: "http://10.92.14.153:2379" 70 | volumeMounts: 71 | - name: docker-sock-path # docker (read-only) 72 | mountPath: /var/run/docker.sock 73 | readOnly: true 74 | - name: usr-src-path # BPF (read-only) 75 | mountPath: /usr/src 76 | readOnly: true 77 | - name: lib-modules-path # BPF (read-only) 78 | mountPath: /lib/modules 79 | readOnly: true 80 | - name: sys-fs-bpf-path # BPF (read-write) 81 | mountPath: /sys/fs/bpf 82 | - name: sys-kernel-debug-path # BPF (read-write) 83 | mountPath: /sys/kernel/debug 84 | # - name: etc-apparmor-d-path # AppArmor (read-write) 85 | # mountPath: /etc/apparmor.d 86 | - name: os-release-path # OS (read-only) 87 | mountPath: /media/root/etc/os-release 88 | readOnly: true 89 | livenessProbe: 90 | exec: 91 | command: 92 | - /bin/bash 93 | - -c 94 | - | 95 | if [ -z $(pgrep kvmsoperator) ]; then 96 | exit 1; 97 | fi; 98 | initialDelaySeconds: 60 99 | periodSeconds: 10 100 | terminationMessagePolicy: File 101 | terminationMessagePath: /dev/termination-log 102 | terminationGracePeriodSeconds: 30 103 | volumes: 104 | - name: docker-sock-path # docker 105 | hostPath: 106 | path: /var/run/docker.sock 107 | type: Socket 108 | - name: usr-src-path # BPF 109 | hostPath: 110 | path: /usr/src 111 | type: Directory 112 | - name: lib-modules-path # BPF 113 | hostPath: 114 | path: /lib/modules 115 | type: Directory 116 | - name: sys-fs-bpf-path # BPF 117 | hostPath: 118 | path: /sys/fs/bpf 119 | type: Directory 120 | - name: sys-kernel-debug-path # BPF 121 | hostPath: 122 | path: /sys/kernel/debug 123 | type: Directory 124 | #- name: etc-apparmor-d-path # AppArmor 125 | # hostPath: 126 | # path: /etc/apparmor.d 127 | # type: DirectoryOrCreate 128 | - name: os-release-path # OS 129 | hostPath: 130 | path: /etc/os-release 131 | type: File 132 | -------------------------------------------------------------------------------- /getting-started/minikube/install_minikube.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # SPDX-License-Identifier: Apache-2.0 3 | # Copyright 2021 Authors of KubeArmor 4 | 5 | # download the latest minikube package 6 | curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube_latest_amd64.deb 7 | 8 | # install minikube 9 | sudo dpkg -i minikube_latest_amd64.deb 10 | 11 | # remove the latest minikube package 12 | rm minikube_latest_amd64.deb 13 | 14 | # download the latest kubectl 15 | curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" 16 | 17 | # install kubectl 18 | sudo mv kubectl /usr/bin 19 | sudo chmod 755 /usr/bin/kubectl 20 | -------------------------------------------------------------------------------- /getting-started/minikube/kvmservice.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: kvmservice 5 | namespace: kube-system 6 | --- 7 | apiVersion: rbac.authorization.k8s.io/v1 8 | kind: ClusterRoleBinding 9 | metadata: 10 | name: kvmservice 11 | roleRef: 12 | apiGroup: rbac.authorization.k8s.io 13 | kind: ClusterRole 14 | name: cluster-admin 15 | subjects: 16 | - kind: ServiceAccount 17 | name: kvmservice 18 | namespace: kube-system 19 | --- 20 | apiVersion: v1 21 | kind: Service 22 | metadata: 23 | name: kvmservice 24 | namespace: kube-system 25 | spec: 26 | selector: 27 | kvmservice-app: kvmservice 28 | ports: 29 | - port: 4040 30 | type: LoadBalancer 31 | externalIPs: 32 | - 192.168.49.2 33 | #192.168.100.112/24 34 | --- 35 | apiVersion: apps/v1 36 | #kind: DaemonSet 37 | kind: Deployment 38 | metadata: 39 | name: kvmservice 40 | namespace: kube-system 41 | labels: 42 | kvmservice-app: kvmservice 43 | spec: 44 | replicas: 1 45 | selector: 46 | matchLabels: 47 | kvmservice-app: kvmservice 48 | template: 49 | metadata: 50 | labels: 51 | kvmservice-app: kvmservice 52 | annotations: 53 | container.apparmor.security.beta.kubernetes.io/kvmservice: unconfined 54 | spec: 55 | serviceAccountName: kvmservice 56 | nodeSelector: 57 | kubernetes.io/os: linux 58 | tolerations: 59 | - operator: Exists 60 | hostPID: true 61 | hostNetwork: true 62 | restartPolicy: Always 63 | dnsPolicy: ClusterFirstWithHostNet 64 | containers: 65 | - name: kvmservice 66 | image: accuknox/kvmservice:v0.1 67 | imagePullPolicy: IfNotPresent 68 | securityContext: 69 | privileged: true 70 | args: ["-port=40400", "-ipAddress='192.168.49.2'"] 71 | env: 72 | - name: CERT_PATH 73 | value: "/var/lib/minikube/certs/etcd/" 74 | ports: 75 | - containerPort: 40400 76 | hostPort: 0 77 | volumeMounts: 78 | - name: docker-sock-path # docker (read-only) 79 | mountPath: /var/run/docker.sock 80 | readOnly: true 81 | - name: usr-src-path # BPF (read-only) 82 | mountPath: /usr/src 83 | readOnly: true 84 | - name: lib-modules-path # BPF (read-only) 85 | mountPath: /lib/modules 86 | readOnly: true 87 | - name: sys-fs-bpf-path # BPF (read-write) 88 | mountPath: /sys/fs/bpf 89 | - name: etc-kubernetes-certs # BPF (read-write) 90 | mountPath: /var/lib/minikube/certs/etcd/ 91 | - name: sys-kernel-debug-path # BPF (read-write) 92 | mountPath: /sys/kernel/debug 93 | # - name: etc-apparmor-d-path # AppArmor (read-write) 94 | # mountPath: /etc/apparmor.d 95 | - name: os-release-path # OS (read-only) 96 | mountPath: /media/root/etc/os-release 97 | readOnly: true 98 | livenessProbe: 99 | exec: 100 | command: 101 | - /bin/bash 102 | - -c 103 | - | 104 | if [ -z $(pgrep kvmservice) ]; then 105 | exit 1; 106 | fi; 107 | initialDelaySeconds: 60 108 | periodSeconds: 10 109 | terminationMessagePolicy: File 110 | terminationMessagePath: /dev/termination-log 111 | terminationGracePeriodSeconds: 30 112 | volumes: 113 | - name: docker-sock-path # docker 114 | hostPath: 115 | path: /var/run/docker.sock 116 | type: Socket 117 | - name: usr-src-path # BPF 118 | hostPath: 119 | path: /usr/src 120 | type: Directory 121 | - name: lib-modules-path # BPF 122 | hostPath: 123 | path: /lib/modules 124 | type: Directory 125 | - name: sys-fs-bpf-path # BPF 126 | hostPath: 127 | path: /sys/fs/bpf 128 | type: Directory 129 | - name: etc-kubernetes-certs 130 | hostPath: 131 | path: /var/lib/minikube/certs/etcd/ 132 | type: Directory 133 | - name: sys-kernel-debug-path # BPF 134 | hostPath: 135 | path: /sys/kernel/debug 136 | type: Directory 137 | #- name: etc-apparmor-d-path # AppArmor 138 | # hostPath: 139 | # path: /etc/apparmor.d 140 | # type: DirectoryOrCreate 141 | - name: os-release-path # OS 142 | hostPath: 143 | path: /etc/os-release 144 | type: File 145 | -------------------------------------------------------------------------------- /getting-started/minikube/kvmsoperator.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: kvmsoperator 5 | namespace: kube-system 6 | --- 7 | apiVersion: rbac.authorization.k8s.io/v1 8 | kind: ClusterRoleBinding 9 | metadata: 10 | name: kvmsoperator 11 | roleRef: 12 | apiGroup: rbac.authorization.k8s.io 13 | kind: ClusterRole 14 | name: cluster-admin 15 | subjects: 16 | - kind: ServiceAccount 17 | name: kvmsoperator 18 | namespace: kube-system 19 | --- 20 | apiVersion: v1 21 | kind: Service 22 | metadata: 23 | name: kvmsoperator 24 | namespace: kube-system 25 | spec: 26 | selector: 27 | kvmsoperator-app: kvmsoperator 28 | ports: 29 | - port: 32770 30 | protocol: TCP 31 | targetPort: 32770 32 | --- 33 | apiVersion: apps/v1 34 | kind: Deployment 35 | metadata: 36 | name: kvmsoperator 37 | namespace: kube-system 38 | labels: 39 | kvmsoperator-app: kvmsoperator 40 | spec: 41 | selector: 42 | matchLabels: 43 | kvmsoperator-app: kvmsoperator 44 | template: 45 | metadata: 46 | labels: 47 | kvmsoperator-app: kvmsoperator 48 | annotations: 49 | container.apparmor.security.beta.kubernetes.io/kvmsoperator: unconfined 50 | spec: 51 | serviceAccountName: kvmsoperator 52 | nodeSelector: 53 | kubernetes.io/os: linux 54 | tolerations: 55 | - operator: Exists 56 | hostPID: true 57 | hostNetwork: true 58 | restartPolicy: Always 59 | dnsPolicy: ClusterFirstWithHostNet 60 | containers: 61 | - name: kvmsoperator 62 | image: accuknox/kvmsoperator:v0.1 63 | imagePullPolicy: IfNotPresent 64 | securityContext: 65 | privileged: true 66 | args: ["-port=40400", "-ipAddress='192.168.49.2'"] 67 | env: 68 | - name: CERT_PATH 69 | value: "/var/lib/minikube/certs/etcd/" 70 | volumeMounts: 71 | - name: docker-sock-path # docker (read-only) 72 | mountPath: /var/run/docker.sock 73 | readOnly: true 74 | - name: usr-src-path # BPF (read-only) 75 | mountPath: /usr/src 76 | readOnly: true 77 | - name: lib-modules-path # BPF (read-only) 78 | mountPath: /lib/modules 79 | readOnly: true 80 | - name: sys-fs-bpf-path # BPF (read-write) 81 | mountPath: /sys/fs/bpf 82 | - name: etc-kubernetes-certs # BPF (read-write) 83 | mountPath: /var/lib/minikube/certs/etcd/ 84 | - name: sys-kernel-debug-path # BPF (read-write) 85 | mountPath: /sys/kernel/debug 86 | - name: os-release-path # OS (read-only) 87 | mountPath: /media/root/etc/os-release 88 | readOnly: true 89 | livenessProbe: 90 | exec: 91 | command: 92 | - /bin/bash 93 | - -c 94 | - | 95 | if [ -z $(pgrep kvmsoperator) ]; then 96 | exit 1; 97 | fi; 98 | initialDelaySeconds: 60 99 | periodSeconds: 10 100 | terminationMessagePolicy: File 101 | terminationMessagePath: /dev/termination-log 102 | terminationGracePeriodSeconds: 30 103 | volumes: 104 | - name: docker-sock-path # docker 105 | hostPath: 106 | path: /var/run/docker.sock 107 | type: Socket 108 | - name: usr-src-path # BPF 109 | hostPath: 110 | path: /usr/src 111 | type: Directory 112 | - name: lib-modules-path # BPF 113 | hostPath: 114 | path: /lib/modules 115 | type: Directory 116 | - name: sys-fs-bpf-path # BPF 117 | hostPath: 118 | path: /sys/fs/bpf 119 | type: Directory 120 | - name: etc-kubernetes-certs 121 | hostPath: 122 | path: /var/lib/minikube/certs/etcd/ 123 | type: Directory 124 | - name: sys-kernel-debug-path # BPF 125 | hostPath: 126 | path: /sys/kernel/debug 127 | type: Directory 128 | - name: os-release-path # OS 129 | hostPath: 130 | path: /etc/os-release 131 | type: File 132 | -------------------------------------------------------------------------------- /getting-started/res/kvmservice-k8s-control-plane.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kubearmor/kvm-service/54a4afef7e011c571537c4cb00659c31b1b1a476/getting-started/res/kvmservice-k8s-control-plane.png -------------------------------------------------------------------------------- /getting-started/res/kvmservice-non-k8s-control-plane.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kubearmor/kvm-service/54a4afef7e011c571537c4cb00659c31b1b1a476/getting-started/res/kvmservice-non-k8s-control-plane.png -------------------------------------------------------------------------------- /helm/templates/security.kubearmor.com_kubearmorexternalworkload.yaml: -------------------------------------------------------------------------------- 1 | 2 | --- 3 | apiVersion: apiextensions.k8s.io/v1 4 | kind: CustomResourceDefinition 5 | metadata: 6 | annotations: 7 | controller-gen.kubebuilder.io/version: v0.2.5 8 | creationTimestamp: null 9 | name: kubearmorexternalworkloads.security.kubearmor.com 10 | spec: 11 | group: security.kubearmor.com 12 | names: 13 | kind: KubeArmorExternalWorkload 14 | listKind: KubeArmorExternalWorkloadList 15 | plural: kubearmorexternalworkloads 16 | shortNames: 17 | - kew 18 | singular: kubearmorexternalworkload 19 | scope: Cluster 20 | versions: 21 | - name: v1 22 | schema: 23 | openAPIV3Schema: 24 | properties: 25 | apiVersion: 26 | description: 'APIVersion defines the versioned schema of this representation 27 | of an object. Servers should convert recognized schemas to the latest 28 | internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' 29 | type: string 30 | kind: 31 | description: 'Kind is a string value representing the REST resource this 32 | object represents. Servers may infer this from the endpoint the client 33 | submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' 34 | type: string 35 | metadata: 36 | type: object 37 | status: 38 | description: Status is the most recent status of the external KubeArmor 39 | workload. It is a read-only field. 40 | properties: 41 | id: 42 | description: ID is the numeric identity allocated for the external 43 | workload. 44 | format: int64 45 | type: integer 46 | ip: 47 | description: IP is the IP address of the workload. Empty if the workload 48 | has not registered. 49 | type: string 50 | type: object 51 | required: 52 | - metadata 53 | type: object 54 | served: true 55 | storage: true 56 | subresources: 57 | status: {} 58 | status: 59 | acceptedNames: 60 | kind: "" 61 | plural: "" 62 | conditions: [] 63 | storedVersions: [] 64 | -------------------------------------------------------------------------------- /helm/templates/security.kubearmor.com_kubearmorexternalworkloads.yaml: -------------------------------------------------------------------------------- 1 | 2 | --- 3 | apiVersion: apiextensions.k8s.io/v1 4 | kind: CustomResourceDefinition 5 | metadata: 6 | annotations: 7 | controller-gen.kubebuilder.io/version: v0.2.5 8 | creationTimestamp: null 9 | name: kubearmorexternalworkloads.security.kubearmor.com 10 | spec: 11 | group: security.kubearmor.com 12 | names: 13 | kind: KubeArmorExternalWorkload 14 | listKind: KubeArmorExternalWorkloadList 15 | plural: kubearmorexternalworkloads 16 | shortNames: 17 | - kew 18 | singular: kubearmorexternalworkload 19 | scope: Cluster 20 | versions: 21 | - name: v1 22 | schema: 23 | openAPIV3Schema: 24 | properties: 25 | apiVersion: 26 | description: 'APIVersion defines the versioned schema of this representation 27 | of an object. Servers should convert recognized schemas to the latest 28 | internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' 29 | type: string 30 | kind: 31 | description: 'Kind is a string value representing the REST resource this 32 | object represents. Servers may infer this from the endpoint the client 33 | submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' 34 | type: string 35 | metadata: 36 | type: object 37 | status: 38 | description: Status is the most recent status of the external KubeArmor 39 | workload. It is a read-only field. 40 | properties: 41 | id: 42 | description: ID is the numeric identity allocated for the external 43 | workload. 44 | format: int64 45 | type: integer 46 | ip: 47 | description: IP is the IP address of the workload. Empty if the workload 48 | has not registered. 49 | type: string 50 | type: object 51 | required: 52 | - metadata 53 | type: object 54 | served: true 55 | storage: true 56 | subresources: 57 | status: {} 58 | status: 59 | acceptedNames: 60 | kind: "" 61 | plural: "" 62 | conditions: [] 63 | storedVersions: [] 64 | -------------------------------------------------------------------------------- /pkg/KubeArmorExternalWorkload/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Authors of KubeArmor 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | # Image URL to use all building/pushing image targets 5 | IMG ?= kubearmor/kubearmor-policy-manager:latest 6 | # Produce CRDs that work back to Kubernetes 1.11 (no version conversion) 7 | CRD_OPTIONS ?= "crd:crdVersions=v1" 8 | 9 | # Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set) 10 | ifeq (,$(shell go env GOBIN)) 11 | GOBIN=$(shell go env GOPATH)/bin 12 | else 13 | GOBIN=$(shell go env GOBIN) 14 | endif 15 | 16 | all: manager 17 | 18 | # Run tests 19 | test: generate fmt vet manifests 20 | go test ./... -coverprofile cover.out 21 | 22 | # Build manager binary 23 | manager: generate fmt vet 24 | go build -o bin/manager main.go 25 | 26 | # Run against the configured Kubernetes cluster in ~/.kube/config 27 | run: generate fmt vet manifests 28 | go run ./main.go 29 | 30 | # Install CRDs into a cluster 31 | install: manifests 32 | kustomize build config/crd | kubectl apply -f - 33 | 34 | # Uninstall CRDs from a cluster 35 | uninstall: manifests 36 | kustomize build config/crd | kubectl delete -f - 37 | 38 | # Deploy controller in the configured Kubernetes cluster in ~/.kube/config 39 | deploy: manifests 40 | cd config/manager && kustomize edit set image controller=${IMG} 41 | kustomize build config/default | kubectl apply -f - 42 | 43 | #security.kubearmor.com_kubearmorexternalworkload.yaml 44 | # Generate manifests e.g. CRD, RBAC etc. 45 | manifests: controller-gen 46 | $(CONTROLLER_GEN) $(CRD_OPTIONS) rbac:roleName=manager-role webhook paths="./..." output:crd:artifacts:config=config/crd/bases 47 | cp config/crd/bases/security.kubearmor.com_kubearmorexternalworkload.yaml ../../helm/templates/security.kubearmor.com_kubearmorexternalworkload.yaml 48 | cp config/crd/bases/security.kubearmor.com_kubearmorexternalworkload.yaml ../../deployments/CRD/KubeArmorExternalWorkload.yaml 49 | 50 | # Generate deployments 51 | deployment: manifests 52 | cd config/manager && kustomize edit set image controller=${IMG} 53 | kustomize build config/default > /tmp/KubeArmorExternalWorkload.yaml 54 | 55 | # Run go fmt against code 56 | fmt: 57 | go fmt ./... 58 | 59 | # Run go vet against code 60 | vet: 61 | go vet ./... 62 | 63 | # Generate code 64 | generate: controller-gen 65 | go mod tidy 66 | $(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./..." 67 | 68 | # Build the docker image 69 | docker-build: 70 | docker build . -t ${IMG} 71 | 72 | # Push the docker image 73 | docker-push: 74 | docker push ${IMG} 75 | 76 | # find or download controller-gen 77 | # download controller-gen if necessary 78 | controller-gen: 79 | ifeq (, $(shell which controller-gen)) 80 | @{ \ 81 | set -e ;\ 82 | CONTROLLER_GEN_TMP_DIR=$$(mktemp -d) ;\ 83 | cd $$CONTROLLER_GEN_TMP_DIR ;\ 84 | go mod init tmp ;\ 85 | go get sigs.k8s.io/controller-tools/cmd/controller-gen@v0.2.5 ;\ 86 | rm -rf $$CONTROLLER_GEN_TMP_DIR ;\ 87 | } 88 | CONTROLLER_GEN=$(GOBIN)/controller-gen 89 | else 90 | CONTROLLER_GEN=$(shell which controller-gen) 91 | endif 92 | 93 | clean: 94 | rm -rf bin go.sum cover.out /tmp/KubeArmorExternalWorkload.yaml 95 | -------------------------------------------------------------------------------- /pkg/KubeArmorExternalWorkload/PROJECT: -------------------------------------------------------------------------------- 1 | domain: kubearmor.com 2 | repo: k8s 3 | resources: 4 | - group: security 5 | kind: KubeArmorExternalWorkload 6 | version: v1 7 | version: "2" 8 | -------------------------------------------------------------------------------- /pkg/KubeArmorExternalWorkload/api/v1/groupversion_info.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Authors of KubeArmor 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // Package v1 contains API Schema definitions for the security v1 API group 5 | // +kubebuilder:object:generate=true 6 | // +groupName=security.kubearmor.com 7 | package v1 8 | 9 | import ( 10 | "k8s.io/apimachinery/pkg/runtime/schema" 11 | "sigs.k8s.io/controller-runtime/pkg/scheme" 12 | ) 13 | 14 | var ( 15 | // GroupVersion is group version used to register these objects 16 | GroupVersion = schema.GroupVersion{Group: "security.kubearmor.com", Version: "v1"} 17 | 18 | // SchemeBuilder is used to add go types to the GroupVersionKind scheme 19 | SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} 20 | 21 | // AddToScheme adds the types in this group-version to the given scheme. 22 | AddToScheme = SchemeBuilder.AddToScheme 23 | ) 24 | -------------------------------------------------------------------------------- /pkg/KubeArmorExternalWorkload/api/v1/kubearmorexternalworkload_types.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Authors of KubeArmor 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package v1 5 | 6 | import ( 7 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 8 | ) 9 | 10 | // +kubebuilder:object:root=true 11 | // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object 12 | // +kubebuilder:resource:singular="kubearmorexternalworkload",path="kubearmorexternalworkloads",scope="Cluster",shortName={kew} 13 | // +kubebuilder:subresource:status 14 | type KubeArmorExternalWorkload struct { 15 | // +k8s:openapi-gen=false 16 | // +deepequal-gen=false 17 | metav1.TypeMeta `json:",inline"` 18 | // +k8s:openapi-gen=false 19 | // +deepequal-gen=false 20 | metav1.ObjectMeta `json:"metadata"` 21 | 22 | // Status is the most recent status of the external KubeArmor workload. 23 | // It is a read-only field. 24 | // 25 | // +deepequal-gen=false 26 | // +kubebuilder:validation:Optional 27 | Status KubeArmorExternalWorkloadStatus `json:"status"` 28 | } 29 | 30 | // KubeArmorExternalWorkloadStatus is the status of a the external KubeArmor workload. 31 | type KubeArmorExternalWorkloadStatus struct { 32 | // ID is the numeric identity allocated for the external workload. 33 | ID uint64 `json:"id,omitempty"` 34 | 35 | // IP is the IP address of the workload. Empty if the workload has not registered. 36 | IP string `json:"ip,omitempty"` 37 | } 38 | 39 | // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object 40 | // +k8s:openapi-gen=false 41 | // +deepequal-gen=false 42 | 43 | // KubeArmorExternalWorkloadList is a list of KubeArmorExternalWorkload objects. 44 | type KubeArmorExternalWorkloadList struct { 45 | metav1.TypeMeta `json:",inline"` 46 | metav1.ListMeta `json:"metadata"` 47 | 48 | // Items is a list of KubeArmorExternalWorkload 49 | Items []KubeArmorExternalWorkload `json:"items"` 50 | } 51 | 52 | func init() { 53 | SchemeBuilder.Register(&KubeArmorExternalWorkload{}, &KubeArmorExternalWorkloadList{}) 54 | } 55 | -------------------------------------------------------------------------------- /pkg/KubeArmorExternalWorkload/api/v1/zz_generated.deepcopy.go: -------------------------------------------------------------------------------- 1 | // +build !ignore_autogenerated 2 | 3 | // Copyright 2021 Authors of KubeArmor 4 | // SPDX-License-Identifier: Apache-2.0 5 | 6 | // Code generated by controller-gen. DO NOT EDIT. 7 | 8 | package v1 9 | 10 | import ( 11 | runtime "k8s.io/apimachinery/pkg/runtime" 12 | ) 13 | 14 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 15 | func (in *KubeArmorExternalWorkload) DeepCopyInto(out *KubeArmorExternalWorkload) { 16 | *out = *in 17 | out.TypeMeta = in.TypeMeta 18 | in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) 19 | out.Status = in.Status 20 | } 21 | 22 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeArmorExternalWorkload. 23 | func (in *KubeArmorExternalWorkload) DeepCopy() *KubeArmorExternalWorkload { 24 | if in == nil { 25 | return nil 26 | } 27 | out := new(KubeArmorExternalWorkload) 28 | in.DeepCopyInto(out) 29 | return out 30 | } 31 | 32 | // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. 33 | func (in *KubeArmorExternalWorkload) DeepCopyObject() runtime.Object { 34 | if c := in.DeepCopy(); c != nil { 35 | return c 36 | } 37 | return nil 38 | } 39 | 40 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 41 | func (in *KubeArmorExternalWorkloadList) DeepCopyInto(out *KubeArmorExternalWorkloadList) { 42 | *out = *in 43 | out.TypeMeta = in.TypeMeta 44 | in.ListMeta.DeepCopyInto(&out.ListMeta) 45 | if in.Items != nil { 46 | in, out := &in.Items, &out.Items 47 | *out = make([]KubeArmorExternalWorkload, len(*in)) 48 | for i := range *in { 49 | (*in)[i].DeepCopyInto(&(*out)[i]) 50 | } 51 | } 52 | } 53 | 54 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeArmorExternalWorkloadList. 55 | func (in *KubeArmorExternalWorkloadList) DeepCopy() *KubeArmorExternalWorkloadList { 56 | if in == nil { 57 | return nil 58 | } 59 | out := new(KubeArmorExternalWorkloadList) 60 | in.DeepCopyInto(out) 61 | return out 62 | } 63 | 64 | // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. 65 | func (in *KubeArmorExternalWorkloadList) DeepCopyObject() runtime.Object { 66 | if c := in.DeepCopy(); c != nil { 67 | return c 68 | } 69 | return nil 70 | } 71 | 72 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 73 | func (in *KubeArmorExternalWorkloadStatus) DeepCopyInto(out *KubeArmorExternalWorkloadStatus) { 74 | *out = *in 75 | } 76 | 77 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeArmorExternalWorkloadStatus. 78 | func (in *KubeArmorExternalWorkloadStatus) DeepCopy() *KubeArmorExternalWorkloadStatus { 79 | if in == nil { 80 | return nil 81 | } 82 | out := new(KubeArmorExternalWorkloadStatus) 83 | in.DeepCopyInto(out) 84 | return out 85 | } 86 | -------------------------------------------------------------------------------- /pkg/KubeArmorExternalWorkload/bin/manager: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kubearmor/kvm-service/54a4afef7e011c571537c4cb00659c31b1b1a476/pkg/KubeArmorExternalWorkload/bin/manager -------------------------------------------------------------------------------- /pkg/KubeArmorExternalWorkload/config/crd/bases/security.kubearmor.com_kubearmorexternalworkload.yaml: -------------------------------------------------------------------------------- 1 | 2 | --- 3 | apiVersion: apiextensions.k8s.io/v1 4 | kind: CustomResourceDefinition 5 | metadata: 6 | annotations: 7 | controller-gen.kubebuilder.io/version: v0.2.5 8 | creationTimestamp: null 9 | name: kubearmorexternalworkloads.security.kubearmor.com 10 | spec: 11 | group: security.kubearmor.com 12 | names: 13 | kind: KubeArmorExternalWorkload 14 | listKind: KubeArmorExternalWorkloadList 15 | plural: kubearmorexternalworkloads 16 | shortNames: 17 | - kew 18 | singular: kubearmorexternalworkload 19 | scope: Cluster 20 | versions: 21 | - name: v1 22 | schema: 23 | openAPIV3Schema: 24 | properties: 25 | apiVersion: 26 | description: 'APIVersion defines the versioned schema of this representation 27 | of an object. Servers should convert recognized schemas to the latest 28 | internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' 29 | type: string 30 | kind: 31 | description: 'Kind is a string value representing the REST resource this 32 | object represents. Servers may infer this from the endpoint the client 33 | submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' 34 | type: string 35 | metadata: 36 | type: object 37 | status: 38 | description: Status is the most recent status of the external KubeArmor 39 | workload. It is a read-only field. 40 | properties: 41 | id: 42 | description: ID is the numeric identity allocated for the external 43 | workload. 44 | format: int64 45 | type: integer 46 | ip: 47 | description: IP is the IP address of the workload. Empty if the workload 48 | has not registered. 49 | type: string 50 | type: object 51 | required: 52 | - metadata 53 | type: object 54 | served: true 55 | storage: true 56 | subresources: 57 | status: {} 58 | status: 59 | acceptedNames: 60 | kind: "" 61 | plural: "" 62 | conditions: [] 63 | storedVersions: [] 64 | -------------------------------------------------------------------------------- /pkg/KubeArmorExternalWorkload/config/crd/bases/security.kubearmor.com_kubearmorexternalworkloads.yaml: -------------------------------------------------------------------------------- 1 | 2 | --- 3 | apiVersion: apiextensions.k8s.io/v1 4 | kind: CustomResourceDefinition 5 | metadata: 6 | annotations: 7 | controller-gen.kubebuilder.io/version: v0.2.5 8 | creationTimestamp: null 9 | name: kubearmorexternalworkloads.security.kubearmor.com 10 | spec: 11 | group: security.kubearmor.com 12 | names: 13 | kind: KubeArmorExternalWorkload 14 | listKind: KubeArmorExternalWorkloadList 15 | plural: kubearmorexternalworkloads 16 | shortNames: 17 | - kew 18 | singular: kubearmorexternalworkload 19 | scope: Cluster 20 | versions: 21 | - name: v1 22 | schema: 23 | openAPIV3Schema: 24 | properties: 25 | apiVersion: 26 | description: 'APIVersion defines the versioned schema of this representation 27 | of an object. Servers should convert recognized schemas to the latest 28 | internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' 29 | type: string 30 | kind: 31 | description: 'Kind is a string value representing the REST resource this 32 | object represents. Servers may infer this from the endpoint the client 33 | submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' 34 | type: string 35 | metadata: 36 | type: object 37 | status: 38 | description: Status is the most recent status of the external KubeArmor 39 | workload. It is a read-only field. 40 | properties: 41 | id: 42 | description: ID is the numeric identity allocated for the external 43 | workload. 44 | format: int64 45 | type: integer 46 | ip: 47 | description: IP is the IP address of the workload. Empty if the workload 48 | has not registered. 49 | type: string 50 | type: object 51 | required: 52 | - metadata 53 | type: object 54 | served: true 55 | storage: true 56 | subresources: 57 | status: {} 58 | status: 59 | acceptedNames: 60 | kind: "" 61 | plural: "" 62 | conditions: [] 63 | storedVersions: [] 64 | -------------------------------------------------------------------------------- /pkg/KubeArmorExternalWorkload/config/crd/kustomization.yaml: -------------------------------------------------------------------------------- 1 | # This kustomization.yaml is not intended to be run by itself, 2 | # since it depends on service name and namespace that are out of this kustomize package. 3 | # It should be run by config/default 4 | resources: 5 | - bases/security.kubearmor.com_kubearmorexternalworkload.yaml 6 | # +kubebuilder:scaffold:crdkustomizeresource 7 | 8 | patchesStrategicMerge: 9 | # [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix. 10 | # patches here are for enabling the conversion webhook for each CRD 11 | #- patches/webhook_in_kubearmorexternalworkload.yaml 12 | # +kubebuilder:scaffold:crdkustomizewebhookpatch 13 | 14 | # [CERTMANAGER] To enable webhook, uncomment all the sections with [CERTMANAGER] prefix. 15 | # patches here are for enabling the CA injection for each CRD 16 | #- patches/cainjection_in_kubearmorexternalworkload.yaml 17 | # +kubebuilder:scaffold:crdkustomizecainjectionpatch 18 | 19 | # the following config is for teaching kustomize how to do kustomization for CRDs. 20 | configurations: 21 | - kustomizeconfig.yaml 22 | -------------------------------------------------------------------------------- /pkg/KubeArmorExternalWorkload/config/crd/kustomizeconfig.yaml: -------------------------------------------------------------------------------- 1 | # This file is for teaching kustomize how to substitute name and namespace reference in CRD 2 | nameReference: 3 | - kind: Service 4 | version: v1 5 | fieldSpecs: 6 | - kind: CustomResourceDefinition 7 | group: apiextensions.k8s.io 8 | path: spec/conversion/webhookClientConfig/service/name 9 | 10 | namespace: 11 | - kind: CustomResourceDefinition 12 | group: apiextensions.k8s.io 13 | path: spec/conversion/webhookClientConfig/service/namespace 14 | create: false 15 | 16 | varReference: 17 | - path: metadata/annotations 18 | -------------------------------------------------------------------------------- /pkg/KubeArmorExternalWorkload/config/default/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - manager.yaml 3 | apiVersion: kustomize.config.k8s.io/v1beta1 4 | kind: Kustomization 5 | images: 6 | - name: controller 7 | newName: kubearmor/kubearmor-external-workload-policy-manager 8 | newTag: latest 9 | -------------------------------------------------------------------------------- /pkg/KubeArmorExternalWorkload/config/default/manager.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | labels: 5 | control-plane: controller-manager 6 | name: system 7 | --- 8 | apiVersion: apps/v1 9 | kind: Deployment 10 | metadata: 11 | name: controller-manager 12 | namespace: system 13 | labels: 14 | control-plane: controller-manager 15 | spec: 16 | selector: 17 | matchLabels: 18 | control-plane: controller-manager 19 | replicas: 1 20 | template: 21 | metadata: 22 | labels: 23 | control-plane: controller-manager 24 | spec: 25 | containers: 26 | - command: 27 | - /manager 28 | args: 29 | - --enable-leader-election 30 | image: kubearmor/kubearmor-external-workload-policy-manager:latest 31 | name: manager 32 | resources: 33 | limits: 34 | cpu: 100m 35 | memory: 30Mi 36 | requests: 37 | cpu: 100m 38 | memory: 20Mi 39 | terminationGracePeriodSeconds: 10 40 | -------------------------------------------------------------------------------- /pkg/KubeArmorExternalWorkload/config/manager/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - manager.yaml 3 | apiVersion: kustomize.config.k8s.io/v1beta1 4 | kind: Kustomization 5 | images: 6 | - name: controller 7 | newName: kubearmor/kubearmor-policy-manager 8 | newTag: latest 9 | -------------------------------------------------------------------------------- /pkg/KubeArmorExternalWorkload/config/manager/manager.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | labels: 5 | control-plane: controller-manager 6 | name: system 7 | --- 8 | apiVersion: apps/v1 9 | kind: Deployment 10 | metadata: 11 | name: controller-manager 12 | namespace: system 13 | labels: 14 | control-plane: controller-manager 15 | spec: 16 | selector: 17 | matchLabels: 18 | control-plane: controller-manager 19 | replicas: 1 20 | template: 21 | metadata: 22 | labels: 23 | control-plane: controller-manager 24 | spec: 25 | containers: 26 | - command: 27 | - /manager 28 | args: 29 | - --enable-leader-election 30 | image: kubearmor/kubearmor-external-workload-policy-manager:latest 31 | name: manager 32 | resources: 33 | limits: 34 | cpu: 100m 35 | memory: 30Mi 36 | requests: 37 | cpu: 100m 38 | memory: 20Mi 39 | terminationGracePeriodSeconds: 10 40 | -------------------------------------------------------------------------------- /pkg/KubeArmorExternalWorkload/config/rbac/role.yaml: -------------------------------------------------------------------------------- 1 | 2 | --- 3 | apiVersion: rbac.authorization.k8s.io/v1 4 | kind: ClusterRole 5 | metadata: 6 | creationTimestamp: null 7 | name: manager-role 8 | rules: 9 | - apiGroups: 10 | - security.kubearmor.com 11 | resources: 12 | - kubearmorexternalworkload 13 | verbs: 14 | - create 15 | - delete 16 | - get 17 | - list 18 | - patch 19 | - update 20 | - watch 21 | - apiGroups: 22 | - security.kubearmor.com 23 | resources: 24 | - kubearmorexternalworkloadstatus 25 | verbs: 26 | - get 27 | - patch 28 | - update 29 | -------------------------------------------------------------------------------- /pkg/KubeArmorExternalWorkload/controllers/kubearmorexternalworkload_controller.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Authors of KubeArmor 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package controllers 5 | 6 | import ( 7 | "context" 8 | 9 | "github.com/go-logr/logr" 10 | ctrl "sigs.k8s.io/controller-runtime" 11 | "sigs.k8s.io/controller-runtime/pkg/client" 12 | 13 | securityv1 "github.com/kubearmor/KubeArmor/pkg/KubeArmorExternalWorkload/api/v1" 14 | "k8s.io/apimachinery/pkg/api/errors" 15 | "k8s.io/apimachinery/pkg/runtime" 16 | ) 17 | 18 | // KubeArmorExternalWorkloadReconciler reconciles a KubeArmorExternalWorkload object 19 | type KubeArmorExternalWorkloadReconciler struct { 20 | client.Client 21 | Log logr.Logger 22 | Scheme *runtime.Scheme 23 | } 24 | 25 | // +kubebuilder:rbac:groups=security.kubearmor.com,resources=kubearmorexternalworkload,verbs=get;list;watch;create;update;patch;delete 26 | // +kubebuilder:rbac:groups=security.kubearmor.com,resources=kubearmorexternalworkloadstatus,verbs=get;update;patch 27 | 28 | func (r *KubeArmorExternalWorkloadReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) { 29 | ctx := context.Background() 30 | log := r.Log.WithValues("kubearmorexternalworkload", req.NamespacedName) 31 | 32 | policy := &securityv1.KubeArmorExternalWorkload{} 33 | 34 | if err := r.Get(ctx, req.NamespacedName, policy); err != nil { 35 | log.Info("Invalid KubeArmorExternalWorkload") 36 | if errors.IsNotFound(err) { 37 | return ctrl.Result{}, client.IgnoreNotFound(err) 38 | } 39 | return ctrl.Result{}, err 40 | } 41 | 42 | // Validate KubeArmorExternalWorkload 43 | // if there are some issues in the CRD then delete it and return failure code 44 | //TODO: Handle the yaml spec validation 45 | 46 | log.Info("Fetched KubeArmorExternalWorkload") 47 | return ctrl.Result{}, nil 48 | 49 | } 50 | 51 | func (r *KubeArmorExternalWorkloadReconciler) SetupWithManager(mgr ctrl.Manager) error { 52 | return ctrl.NewControllerManagedBy(mgr). 53 | For(&securityv1.KubeArmorExternalWorkload{}). 54 | Complete(r) 55 | } 56 | -------------------------------------------------------------------------------- /pkg/KubeArmorExternalWorkload/controllers/suite_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Authors of KubeArmor 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package controllers 5 | 6 | import ( 7 | "path/filepath" 8 | "testing" 9 | 10 | . "github.com/onsi/ginkgo" 11 | . "github.com/onsi/gomega" 12 | "sigs.k8s.io/controller-runtime/pkg/client" 13 | "sigs.k8s.io/controller-runtime/pkg/envtest" 14 | "sigs.k8s.io/controller-runtime/pkg/envtest/printer" 15 | logf "sigs.k8s.io/controller-runtime/pkg/log" 16 | "sigs.k8s.io/controller-runtime/pkg/log/zap" 17 | 18 | securityv1 "github.com/kubearmor/KubeArmor/pkg/KubeArmorExternalWorkload/api/v1" 19 | "k8s.io/client-go/kubernetes/scheme" 20 | "k8s.io/client-go/rest" 21 | // +kubebuilder:scaffold:imports 22 | ) 23 | 24 | // These tests use Ginkgo (BDD-style Go testing framework). Refer to 25 | // http://onsi.github.io/ginkgo/ to learn more about Ginkgo. 26 | 27 | var cfg *rest.Config 28 | var k8sClient client.Client 29 | var testEnv *envtest.Environment 30 | 31 | func TestAPIs(t *testing.T) { 32 | RegisterFailHandler(Fail) 33 | 34 | RunSpecsWithDefaultAndCustomReporters(t, 35 | "Controller Suite", 36 | []Reporter{printer.NewlineReporter{}}) 37 | } 38 | 39 | var _ = BeforeSuite(func(done Done) { 40 | logf.SetLogger(zap.LoggerTo(GinkgoWriter, true)) 41 | 42 | By("bootstrapping test environment") 43 | testEnv = &envtest.Environment{ 44 | CRDDirectoryPaths: []string{filepath.Join("..", "config", "crd", "bases")}, 45 | } 46 | 47 | var err error 48 | cfg, err = testEnv.Start() 49 | Expect(err).ToNot(HaveOccurred()) 50 | Expect(cfg).ToNot(BeNil()) 51 | 52 | err = securityv1.AddToScheme(scheme.Scheme) 53 | Expect(err).NotTo(HaveOccurred()) 54 | 55 | // +kubebuilder:scaffold:scheme 56 | 57 | k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme}) 58 | Expect(err).ToNot(HaveOccurred()) 59 | Expect(k8sClient).ToNot(BeNil()) 60 | 61 | close(done) 62 | }, 60) 63 | 64 | var _ = AfterSuite(func() { 65 | By("tearing down the test environment") 66 | err := testEnv.Stop() 67 | Expect(err).ToNot(HaveOccurred()) 68 | }) 69 | -------------------------------------------------------------------------------- /pkg/KubeArmorExternalWorkload/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/kubearmor/KubeArmor/pkg/KubeArmorExternalWorkload 2 | 3 | go 1.13 4 | 5 | require ( 6 | github.com/go-logr/logr v0.1.0 7 | github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef // indirect 8 | github.com/google/go-cmp v0.5.2 // indirect 9 | github.com/google/uuid v1.1.2 // indirect 10 | github.com/kr/text v0.2.0 // indirect 11 | github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect 12 | github.com/onsi/ginkgo v1.11.0 13 | github.com/onsi/gomega v1.8.1 14 | github.com/pkg/errors v0.9.1 // indirect 15 | github.com/stretchr/testify v1.6.1 // indirect 16 | go.uber.org/atomic v1.4.0 // indirect 17 | golang.org/x/net v0.0.0-20201110031124-69a78807bb2b // indirect 18 | golang.org/x/text v0.3.4 // indirect 19 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect 20 | gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect 21 | gopkg.in/yaml.v2 v2.3.0 // indirect 22 | k8s.io/apimachinery v0.17.2 23 | k8s.io/client-go v0.17.2 24 | sigs.k8s.io/controller-runtime v0.5.0 25 | sigs.k8s.io/yaml v1.2.0 // indirect 26 | ) 27 | -------------------------------------------------------------------------------- /pkg/KubeArmorExternalWorkload/hack/boilerplate.go.txt: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Authors of KubeArmor 2 | // SPDX-License-Identifier: Apache-2.0 3 | -------------------------------------------------------------------------------- /pkg/KubeArmorExternalWorkload/kustomize: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kubearmor/kvm-service/54a4afef7e011c571537c4cb00659c31b1b1a476/pkg/KubeArmorExternalWorkload/kustomize -------------------------------------------------------------------------------- /pkg/KubeArmorExternalWorkload/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Authors of KubeArmor 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package main 5 | 6 | import ( 7 | "flag" 8 | "os" 9 | 10 | ctrl "sigs.k8s.io/controller-runtime" 11 | "sigs.k8s.io/controller-runtime/pkg/log/zap" 12 | 13 | "k8s.io/apimachinery/pkg/runtime" 14 | clientgoscheme "k8s.io/client-go/kubernetes/scheme" 15 | _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" 16 | 17 | securityv1 "github.com/kubearmor/KubeArmor/pkg/KubeArmorExternalWorkload/api/v1" 18 | "github.com/kubearmor/KubeArmor/pkg/KubeArmorExternalWorkload/controllers" 19 | // +kubebuilder:scaffold:imports 20 | ) 21 | 22 | var ( 23 | scheme = runtime.NewScheme() 24 | setupLog = ctrl.Log.WithName("setup") 25 | ) 26 | 27 | func init() { 28 | _ = clientgoscheme.AddToScheme(scheme) 29 | 30 | _ = securityv1.AddToScheme(scheme) 31 | // +kubebuilder:scaffold:scheme 32 | } 33 | 34 | func main() { 35 | var metricsAddr string 36 | var enableLeaderElection bool 37 | flag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.") 38 | flag.BoolVar(&enableLeaderElection, "enable-leader-election", false, 39 | "Enable leader election for controller manager. "+ 40 | "Enabling this will ensure there is only one active controller manager.") 41 | flag.Parse() 42 | 43 | ctrl.SetLogger(zap.New(zap.UseDevMode(true))) 44 | 45 | mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ 46 | Scheme: scheme, 47 | MetricsBindAddress: metricsAddr, 48 | Port: 9443, 49 | LeaderElection: enableLeaderElection, 50 | LeaderElectionID: "62bbde7f.kubearmor.com", 51 | }) 52 | if err != nil { 53 | setupLog.Error(err, "unable to start manager") 54 | os.Exit(1) 55 | } 56 | 57 | if err = (&controllers.KubeArmorExternalWorkloadReconciler{ 58 | Client: mgr.GetClient(), 59 | Log: ctrl.Log.WithName("controllers").WithName("KubeArmorExternalWorkload"), 60 | Scheme: mgr.GetScheme(), 61 | }).SetupWithManager(mgr); err != nil { 62 | setupLog.Error(err, "unable to create controller", "controller", "KubeArmorExternalWorkload") 63 | os.Exit(1) 64 | } 65 | // +kubebuilder:scaffold:builder 66 | 67 | setupLog.Info("starting manager") 68 | if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil { 69 | setupLog.Error(err, "problem running manager") 70 | os.Exit(1) 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /pkg/KubeArmorHostPolicy/.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | bin 8 | 9 | # Test binary, build with `go test -c` 10 | *.test 11 | 12 | # Output of the go coverage tool, specifically when used with LiteIDE 13 | *.out 14 | 15 | # Kubernetes Generated files - skip generated files, except for vendored files 16 | !vendor/**/zz_generated.* 17 | 18 | # editor and IDE paraphernalia 19 | .idea 20 | *.swp 21 | *.swo 22 | *~ 23 | -------------------------------------------------------------------------------- /pkg/KubeArmorHostPolicy/Dockerfile: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | # Copyright 2021 Authors of KubeArmor 3 | 4 | # Build the manager binary 5 | FROM golang:1.13 as builder 6 | 7 | WORKDIR /workspace 8 | 9 | # Copy the Go Modules manifests 10 | COPY go.mod go.mod 11 | COPY go.sum go.sum 12 | 13 | # cache deps before building and copying source so that we don't need to re-download as much 14 | # and so that source changes don't invalidate our downloaded layer 15 | RUN go mod download 16 | 17 | # Copy the go source 18 | COPY main.go main.go 19 | COPY api/ api/ 20 | COPY controllers/ controllers/ 21 | 22 | # Build 23 | RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GO111MODULE=on go build -a -o manager main.go 24 | 25 | # Use distroless as minimal base image to package the manager binary 26 | # Refer to https://github.com/GoogleContainerTools/distroless for more details 27 | FROM gcr.io/distroless/static:nonroot 28 | WORKDIR / 29 | COPY --from=builder /workspace/manager . 30 | USER nonroot:nonroot 31 | 32 | ENTRYPOINT ["/manager"] 33 | -------------------------------------------------------------------------------- /pkg/KubeArmorHostPolicy/Makefile: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | # Copyright 2021 Authors of KubeArmor 3 | 4 | # Image URL to use all building/pushing image targets 5 | IMG ?= kubearmor/kubearmor-host-policy-manager:latest 6 | # Produce CRDs that work back to Kubernetes 1.11 (no version conversion) 7 | CRD_OPTIONS ?= "crd:crdVersions=v1" 8 | 9 | # Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set) 10 | ifeq (,$(shell go env GOBIN)) 11 | GOBIN=$(shell go env GOPATH)/bin 12 | else 13 | GOBIN=$(shell go env GOBIN) 14 | endif 15 | 16 | all: manager 17 | 18 | # Run tests 19 | test: generate fmt vet manifests 20 | go test ./... -coverprofile cover.out 21 | 22 | # Build manager binary 23 | manager: generate fmt vet 24 | go build -o bin/manager main.go 25 | 26 | # Run against the configured Kubernetes cluster in ~/.kube/config 27 | run: generate fmt vet manifests 28 | go run ./main.go 29 | 30 | # Install CRDs into a cluster 31 | install: manifests 32 | kustomize build config/crd | kubectl apply -f - 33 | 34 | # Uninstall CRDs from a cluster 35 | uninstall: manifests 36 | kustomize build config/crd | kubectl delete -f - 37 | 38 | # Deploy controller in the configured Kubernetes cluster in ~/.kube/config 39 | deploy: manifests 40 | cd config/manager && kustomize edit set image controller=${IMG} 41 | kustomize build config/default | kubectl apply -f - 42 | 43 | # Generate manifests e.g. CRD, RBAC etc. 44 | manifests: controller-gen 45 | $(CONTROLLER_GEN) $(CRD_OPTIONS) rbac:roleName=manager-role webhook paths="./..." output:crd:artifacts:config=config/crd/bases 46 | sed -i 's/scope: Namespaced/scope: Cluster/g' config/crd/bases/security.kubearmor.com_kubearmorhostpolicies.yaml 47 | cp config/crd/bases/security.kubearmor.com_kubearmorhostpolicies.yaml ../../helm/templates/security.kubearmor.com_kubearmorhostpolicies.yaml 48 | cp config/crd/bases/security.kubearmor.com_kubearmorhostpolicies.yaml ../../deployments/CRD/KubeArmorHostPolicy.yaml 49 | 50 | # Generate deployments 51 | deployment: manifests 52 | cd config/manager && kustomize edit set image controller=${IMG} 53 | kustomize build config/default > /tmp/KubeArmorHostPolicy.yaml 54 | 55 | # Run go fmt against code 56 | fmt: 57 | go fmt ./... 58 | 59 | # Run go vet against code 60 | vet: 61 | go vet ./... 62 | 63 | # Generate code 64 | generate: controller-gen 65 | go mod tidy 66 | $(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./..." 67 | 68 | # Build the docker image 69 | docker-build: 70 | docker build . -t ${IMG} 71 | 72 | # Push the docker image 73 | docker-push: 74 | docker push ${IMG} 75 | 76 | # find or download controller-gen 77 | # download controller-gen if necessary 78 | controller-gen: 79 | ifeq (, $(shell which controller-gen)) 80 | @{ \ 81 | set -e ;\ 82 | CONTROLLER_GEN_TMP_DIR=$$(mktemp -d) ;\ 83 | cd $$CONTROLLER_GEN_TMP_DIR ;\ 84 | go mod init tmp ;\ 85 | go get sigs.k8s.io/controller-tools/cmd/controller-gen@v0.2.5 ;\ 86 | rm -rf $$CONTROLLER_GEN_TMP_DIR ;\ 87 | } 88 | CONTROLLER_GEN=$(GOBIN)/controller-gen 89 | else 90 | CONTROLLER_GEN=$(shell which controller-gen) 91 | endif 92 | 93 | clean: 94 | rm -rf bin go.sum cover.out /tmp/KubeArmorHostPolicy.yaml 95 | -------------------------------------------------------------------------------- /pkg/KubeArmorHostPolicy/PROJECT: -------------------------------------------------------------------------------- 1 | domain: kubearmor.com 2 | repo: k8s 3 | resources: 4 | - group: security 5 | kind: KubeArmorHostPolicy 6 | version: v1 7 | version: "2" 8 | -------------------------------------------------------------------------------- /pkg/KubeArmorHostPolicy/api/v1/groupversion_info.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2021 Authors of KubeArmor 3 | 4 | // Package v1 contains API Schema definitions for the security v1 API group 5 | // +kubebuilder:object:generate=true 6 | // +groupName=security.kubearmor.com 7 | package v1 8 | 9 | import ( 10 | "k8s.io/apimachinery/pkg/runtime/schema" 11 | "sigs.k8s.io/controller-runtime/pkg/scheme" 12 | ) 13 | 14 | var ( 15 | // GroupVersion is group version used to register these objects 16 | GroupVersion = schema.GroupVersion{Group: "security.kubearmor.com", Version: "v1"} 17 | 18 | // SchemeBuilder is used to add go types to the GroupVersionKind scheme 19 | SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} 20 | 21 | // AddToScheme adds the types in this group-version to the given scheme. 22 | AddToScheme = SchemeBuilder.AddToScheme 23 | ) 24 | -------------------------------------------------------------------------------- /pkg/KubeArmorHostPolicy/config/certmanager/certificate.yaml: -------------------------------------------------------------------------------- 1 | # The following manifests contain a self-signed issuer CR and a certificate CR. 2 | # More document can be found at https://docs.cert-manager.io 3 | # WARNING: Targets CertManager 0.11 check https://docs.cert-manager.io/en/latest/tasks/upgrading/index.html for 4 | # breaking changes 5 | apiVersion: cert-manager.io/v1alpha2 6 | kind: Issuer 7 | metadata: 8 | name: selfsigned-issuer 9 | namespace: system 10 | spec: 11 | selfSigned: {} 12 | --- 13 | apiVersion: cert-manager.io/v1alpha2 14 | kind: Certificate 15 | metadata: 16 | name: serving-cert # this name should match the one appeared in kustomizeconfig.yaml 17 | namespace: system 18 | spec: 19 | # $(SERVICE_NAME) and $(SERVICE_NAMESPACE) will be substituted by kustomize 20 | dnsNames: 21 | - $(SERVICE_NAME).$(SERVICE_NAMESPACE).svc 22 | - $(SERVICE_NAME).$(SERVICE_NAMESPACE).svc.cluster.local 23 | issuerRef: 24 | kind: Issuer 25 | name: selfsigned-issuer 26 | secretName: webhook-server-cert # this secret will not be prefixed, since it's not managed by kustomize 27 | -------------------------------------------------------------------------------- /pkg/KubeArmorHostPolicy/config/certmanager/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - certificate.yaml 3 | 4 | configurations: 5 | - kustomizeconfig.yaml 6 | -------------------------------------------------------------------------------- /pkg/KubeArmorHostPolicy/config/certmanager/kustomizeconfig.yaml: -------------------------------------------------------------------------------- 1 | # This configuration is for teaching kustomize how to update name ref and var substitution 2 | nameReference: 3 | - kind: Issuer 4 | group: cert-manager.io 5 | fieldSpecs: 6 | - kind: Certificate 7 | group: cert-manager.io 8 | path: spec/issuerRef/name 9 | 10 | varReference: 11 | - kind: Certificate 12 | group: cert-manager.io 13 | path: spec/commonName 14 | - kind: Certificate 15 | group: cert-manager.io 16 | path: spec/dnsNames 17 | -------------------------------------------------------------------------------- /pkg/KubeArmorHostPolicy/config/crd/kustomization.yaml: -------------------------------------------------------------------------------- 1 | # This kustomization.yaml is not intended to be run by itself, 2 | # since it depends on service name and namespace that are out of this kustomize package. 3 | # It should be run by config/default 4 | resources: 5 | - bases/security.kubearmor.com_kubearmorhostpolicies.yaml 6 | # +kubebuilder:scaffold:crdkustomizeresource 7 | 8 | patchesStrategicMerge: 9 | # [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix. 10 | # patches here are for enabling the conversion webhook for each CRD 11 | #- patches/webhook_in_kubearmorhostpolicies.yaml 12 | # +kubebuilder:scaffold:crdkustomizewebhookpatch 13 | 14 | # [CERTMANAGER] To enable webhook, uncomment all the sections with [CERTMANAGER] prefix. 15 | # patches here are for enabling the CA injection for each CRD 16 | #- patches/cainjection_in_kubearmorhostpolicies.yaml 17 | # +kubebuilder:scaffold:crdkustomizecainjectionpatch 18 | 19 | # the following config is for teaching kustomize how to do kustomization for CRDs. 20 | configurations: 21 | - kustomizeconfig.yaml 22 | -------------------------------------------------------------------------------- /pkg/KubeArmorHostPolicy/config/crd/kustomizeconfig.yaml: -------------------------------------------------------------------------------- 1 | # This file is for teaching kustomize how to substitute name and namespace reference in CRD 2 | nameReference: 3 | - kind: Service 4 | version: v1 5 | fieldSpecs: 6 | - kind: CustomResourceDefinition 7 | group: apiextensions.k8s.io 8 | path: spec/conversion/webhookClientConfig/service/name 9 | 10 | namespace: 11 | - kind: CustomResourceDefinition 12 | group: apiextensions.k8s.io 13 | path: spec/conversion/webhookClientConfig/service/namespace 14 | create: false 15 | 16 | varReference: 17 | - path: metadata/annotations 18 | -------------------------------------------------------------------------------- /pkg/KubeArmorHostPolicy/config/crd/patches/cainjection_in_kubearmorhostpolicies.yaml: -------------------------------------------------------------------------------- 1 | # The following patch adds a directive for certmanager to inject CA into the CRD 2 | # CRD conversion requires k8s 1.13 or later. 3 | apiVersion: apiextensions.k8s.io/v1beta1 4 | kind: CustomResourceDefinition 5 | metadata: 6 | annotations: 7 | cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) 8 | name: kubearmorhostpolicies.security.kubearmor.com 9 | -------------------------------------------------------------------------------- /pkg/KubeArmorHostPolicy/config/crd/patches/webhook_in_kubearmorhostpolicies.yaml: -------------------------------------------------------------------------------- 1 | # The following patch enables conversion webhook for CRD 2 | # CRD conversion requires k8s 1.13 or later. 3 | apiVersion: apiextensions.k8s.io/v1beta1 4 | kind: CustomResourceDefinition 5 | metadata: 6 | name: kubearmorhostpolicies.security.kubearmor.com 7 | spec: 8 | conversion: 9 | strategy: Webhook 10 | webhookClientConfig: 11 | # this is "\n" used as a placeholder, otherwise it will be rejected by the apiserver for being blank, 12 | # but we're going to set it later using the cert-manager (or potentially a patch if not using cert-manager) 13 | caBundle: Cg== 14 | service: 15 | namespace: system 16 | name: webhook-service 17 | path: /convert 18 | -------------------------------------------------------------------------------- /pkg/KubeArmorHostPolicy/config/default/kustomization.yaml: -------------------------------------------------------------------------------- 1 | # Adds namespace to all resources. 2 | namespace: kube-system 3 | 4 | # Value of this field is prepended to the 5 | # names of all resources, e.g. a deployment named 6 | # "wordpress" becomes "alices-wordpress". 7 | # Note that it should also match with the prefix (text before '-') of the namespace 8 | # field above. 9 | namePrefix: kubearmor-host-policy- 10 | 11 | # Labels to add to all resources and selectors. 12 | #commonLabels: 13 | # someName: someValue 14 | 15 | bases: 16 | - ../crd 17 | - ../rbac 18 | - ../manager 19 | # [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in 20 | # crd/kustomization.yaml 21 | #- ../webhook 22 | # [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. 'WEBHOOK' components are required. 23 | #- ../certmanager 24 | # [PROMETHEUS] To enable prometheus monitor, uncomment all sections with 'PROMETHEUS'. 25 | #- ../prometheus 26 | 27 | patchesStrategicMerge: 28 | # Protect the /metrics endpoint by putting it behind auth. 29 | # If you want your controller-manager to expose the /metrics 30 | # endpoint w/o any authn/z, please comment the following line. 31 | - manager_auth_proxy_patch.yaml 32 | 33 | # [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in 34 | # crd/kustomization.yaml 35 | #- manager_webhook_patch.yaml 36 | 37 | # [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. 38 | # Uncomment 'CERTMANAGER' sections in crd/kustomization.yaml to enable the CA injection in the admission webhooks. 39 | # 'CERTMANAGER' needs to be enabled to use ca injection 40 | #- webhookcainjection_patch.yaml 41 | 42 | # the following config is for teaching kustomize how to do var substitution 43 | vars: 44 | # [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER' prefix. 45 | #- name: CERTIFICATE_NAMESPACE # namespace of the certificate CR 46 | # objref: 47 | # kind: Certificate 48 | # group: cert-manager.io 49 | # version: v1alpha2 50 | # name: serving-cert # this name should match the one in certificate.yaml 51 | # fieldref: 52 | # fieldpath: metadata.namespace 53 | #- name: CERTIFICATE_NAME 54 | # objref: 55 | # kind: Certificate 56 | # group: cert-manager.io 57 | # version: v1alpha2 58 | # name: serving-cert # this name should match the one in certificate.yaml 59 | #- name: SERVICE_NAMESPACE # namespace of the service 60 | # objref: 61 | # kind: Service 62 | # version: v1 63 | # name: webhook-service 64 | # fieldref: 65 | # fieldpath: metadata.namespace 66 | #- name: SERVICE_NAME 67 | # objref: 68 | # kind: Service 69 | # version: v1 70 | # name: webhook-service 71 | -------------------------------------------------------------------------------- /pkg/KubeArmorHostPolicy/config/default/manager_auth_proxy_patch.yaml: -------------------------------------------------------------------------------- 1 | # This patch inject a sidecar container which is a HTTP proxy for the 2 | # controller manager, it performs RBAC authorization against the Kubernetes API using SubjectAccessReviews. 3 | apiVersion: apps/v1 4 | kind: Deployment 5 | metadata: 6 | name: controller-manager 7 | namespace: system 8 | spec: 9 | template: 10 | spec: 11 | containers: 12 | - name: kube-rbac-proxy 13 | image: gcr.io/kubebuilder/kube-rbac-proxy:v0.5.0 14 | args: 15 | - "--secure-listen-address=0.0.0.0:8443" 16 | - "--upstream=http://127.0.0.1:8080/" 17 | - "--logtostderr=true" 18 | - "--v=10" 19 | ports: 20 | - containerPort: 8443 21 | name: https 22 | - name: manager 23 | args: 24 | - "--metrics-addr=127.0.0.1:8080" 25 | - "--enable-leader-election" 26 | -------------------------------------------------------------------------------- /pkg/KubeArmorHostPolicy/config/default/manager_webhook_patch.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: controller-manager 5 | namespace: system 6 | spec: 7 | template: 8 | spec: 9 | containers: 10 | - name: manager 11 | ports: 12 | - containerPort: 9443 13 | name: webhook-server 14 | protocol: TCP 15 | volumeMounts: 16 | - mountPath: /tmp/k8s-webhook-server/serving-certs 17 | name: cert 18 | readOnly: true 19 | volumes: 20 | - name: cert 21 | secret: 22 | defaultMode: 420 23 | secretName: webhook-server-cert 24 | -------------------------------------------------------------------------------- /pkg/KubeArmorHostPolicy/config/default/webhookcainjection_patch.yaml: -------------------------------------------------------------------------------- 1 | # This patch add annotation to admission webhook config and 2 | # the variables $(CERTIFICATE_NAMESPACE) and $(CERTIFICATE_NAME) will be substituted by kustomize. 3 | apiVersion: admissionregistration.k8s.io/v1beta1 4 | kind: MutatingWebhookConfiguration 5 | metadata: 6 | name: mutating-webhook-configuration 7 | annotations: 8 | cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) 9 | --- 10 | apiVersion: admissionregistration.k8s.io/v1beta1 11 | kind: ValidatingWebhookConfiguration 12 | metadata: 13 | name: validating-webhook-configuration 14 | annotations: 15 | cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) 16 | -------------------------------------------------------------------------------- /pkg/KubeArmorHostPolicy/config/manager/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - manager.yaml 3 | apiVersion: kustomize.config.k8s.io/v1beta1 4 | kind: Kustomization 5 | images: 6 | - name: controller 7 | newName: kubearmor/kubearmor-host-policy-manager 8 | newTag: latest 9 | -------------------------------------------------------------------------------- /pkg/KubeArmorHostPolicy/config/manager/manager.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | labels: 5 | control-plane: controller-manager 6 | name: system 7 | --- 8 | apiVersion: apps/v1 9 | kind: Deployment 10 | metadata: 11 | name: controller-manager 12 | namespace: system 13 | labels: 14 | control-plane: controller-manager 15 | spec: 16 | selector: 17 | matchLabels: 18 | control-plane: controller-manager 19 | replicas: 1 20 | template: 21 | metadata: 22 | labels: 23 | control-plane: controller-manager 24 | spec: 25 | containers: 26 | - command: 27 | - /manager 28 | args: 29 | - --enable-leader-election 30 | image: kubearmor/kubearmor-host-policy-manager:latest 31 | name: manager 32 | resources: 33 | limits: 34 | cpu: 100m 35 | memory: 30Mi 36 | requests: 37 | cpu: 100m 38 | memory: 20Mi 39 | terminationGracePeriodSeconds: 10 40 | -------------------------------------------------------------------------------- /pkg/KubeArmorHostPolicy/config/prometheus/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - monitor.yaml 3 | -------------------------------------------------------------------------------- /pkg/KubeArmorHostPolicy/config/prometheus/monitor.yaml: -------------------------------------------------------------------------------- 1 | # Prometheus Monitor Service (Metrics) 2 | apiVersion: monitoring.coreos.com/v1 3 | kind: ServiceMonitor 4 | metadata: 5 | labels: 6 | control-plane: controller-manager 7 | name: controller-manager-metrics-monitor 8 | namespace: system 9 | spec: 10 | endpoints: 11 | - path: /metrics 12 | port: https 13 | selector: 14 | matchLabels: 15 | control-plane: controller-manager 16 | -------------------------------------------------------------------------------- /pkg/KubeArmorHostPolicy/config/rbac/auth_proxy_client_clusterrole.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1beta1 2 | kind: ClusterRole 3 | metadata: 4 | name: metrics-reader 5 | rules: 6 | - nonResourceURLs: ["/metrics"] 7 | verbs: ["get"] 8 | -------------------------------------------------------------------------------- /pkg/KubeArmorHostPolicy/config/rbac/auth_proxy_role.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | name: proxy-role 5 | rules: 6 | - apiGroups: ["authentication.k8s.io"] 7 | resources: 8 | - tokenreviews 9 | verbs: ["create"] 10 | - apiGroups: ["authorization.k8s.io"] 11 | resources: 12 | - subjectaccessreviews 13 | verbs: ["create"] 14 | -------------------------------------------------------------------------------- /pkg/KubeArmorHostPolicy/config/rbac/auth_proxy_role_binding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | name: proxy-rolebinding 5 | roleRef: 6 | apiGroup: rbac.authorization.k8s.io 7 | kind: ClusterRole 8 | name: proxy-role 9 | subjects: 10 | - kind: ServiceAccount 11 | name: default 12 | namespace: system 13 | -------------------------------------------------------------------------------- /pkg/KubeArmorHostPolicy/config/rbac/auth_proxy_service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | labels: 5 | control-plane: controller-manager 6 | name: controller-manager-metrics-service 7 | namespace: system 8 | spec: 9 | ports: 10 | - name: https 11 | port: 8443 12 | targetPort: https 13 | selector: 14 | control-plane: controller-manager 15 | -------------------------------------------------------------------------------- /pkg/KubeArmorHostPolicy/config/rbac/kubearmorhostpolicy_editor_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions for end users to edit kubearmorhostpolicies. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | name: kubearmorhostpolicy-editor-role 6 | rules: 7 | - apiGroups: 8 | - security.kubearmor.com 9 | resources: 10 | - kubearmorhostpolicies 11 | verbs: 12 | - create 13 | - delete 14 | - get 15 | - list 16 | - patch 17 | - update 18 | - watch 19 | - apiGroups: 20 | - security.kubearmor.com 21 | resources: 22 | - kubearmorhostpolicies/status 23 | verbs: 24 | - get 25 | -------------------------------------------------------------------------------- /pkg/KubeArmorHostPolicy/config/rbac/kubearmorhostpolicy_viewer_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions for end users to view kubearmorhostpolicies. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | name: kubearmorhostpolicy-viewer-role 6 | rules: 7 | - apiGroups: 8 | - security.kubearmor.com 9 | resources: 10 | - kubearmorhostpolicies 11 | verbs: 12 | - get 13 | - list 14 | - watch 15 | - apiGroups: 16 | - security.kubearmor.com 17 | resources: 18 | - kubearmorhostpolicies/status 19 | verbs: 20 | - get 21 | -------------------------------------------------------------------------------- /pkg/KubeArmorHostPolicy/config/rbac/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - role.yaml 3 | - role_binding.yaml 4 | - leader_election_role.yaml 5 | - leader_election_role_binding.yaml 6 | # Comment the following 4 lines if you want to disable 7 | # the auth proxy (https://github.com/brancz/kube-rbac-proxy) 8 | # which protects your /metrics endpoint. 9 | - auth_proxy_service.yaml 10 | - auth_proxy_role.yaml 11 | - auth_proxy_role_binding.yaml 12 | - auth_proxy_client_clusterrole.yaml 13 | -------------------------------------------------------------------------------- /pkg/KubeArmorHostPolicy/config/rbac/leader_election_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions to do leader election. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: Role 4 | metadata: 5 | name: leader-election-role 6 | rules: 7 | - apiGroups: 8 | - "" 9 | resources: 10 | - configmaps 11 | verbs: 12 | - get 13 | - list 14 | - watch 15 | - create 16 | - update 17 | - patch 18 | - delete 19 | - apiGroups: 20 | - "" 21 | resources: 22 | - configmaps/status 23 | verbs: 24 | - get 25 | - update 26 | - patch 27 | - apiGroups: 28 | - "" 29 | resources: 30 | - events 31 | verbs: 32 | - create 33 | -------------------------------------------------------------------------------- /pkg/KubeArmorHostPolicy/config/rbac/leader_election_role_binding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: RoleBinding 3 | metadata: 4 | name: leader-election-rolebinding 5 | roleRef: 6 | apiGroup: rbac.authorization.k8s.io 7 | kind: Role 8 | name: leader-election-role 9 | subjects: 10 | - kind: ServiceAccount 11 | name: default 12 | namespace: system 13 | -------------------------------------------------------------------------------- /pkg/KubeArmorHostPolicy/config/rbac/role.yaml: -------------------------------------------------------------------------------- 1 | 2 | --- 3 | apiVersion: rbac.authorization.k8s.io/v1 4 | kind: ClusterRole 5 | metadata: 6 | creationTimestamp: null 7 | name: manager-role 8 | rules: 9 | - apiGroups: 10 | - security.kubearmor.com 11 | resources: 12 | - kubearmorhostpolicies 13 | verbs: 14 | - create 15 | - delete 16 | - get 17 | - list 18 | - patch 19 | - update 20 | - watch 21 | - apiGroups: 22 | - security.kubearmor.com 23 | resources: 24 | - kubearmorhostpolicies/status 25 | verbs: 26 | - get 27 | - patch 28 | - update 29 | -------------------------------------------------------------------------------- /pkg/KubeArmorHostPolicy/config/rbac/role_binding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | name: manager-rolebinding 5 | roleRef: 6 | apiGroup: rbac.authorization.k8s.io 7 | kind: ClusterRole 8 | name: manager-role 9 | subjects: 10 | - kind: ServiceAccount 11 | name: default 12 | namespace: system 13 | -------------------------------------------------------------------------------- /pkg/KubeArmorHostPolicy/config/samples/security_v1_kubearmorhostpolicy.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: security.kubearmor.com/v1 2 | kind: KubeArmorHostPolicy 3 | metadata: 4 | name: hsp-kubearmor-dev-proc-path-block 5 | spec: 6 | nodeSelector: 7 | matchLabels: 8 | kubernetes.io/hostname: kubearmor-dev 9 | severity: 5 10 | process: 11 | matchPaths: 12 | - path: /usr/bin/screen # try screen -h 13 | action: 14 | Block 15 | -------------------------------------------------------------------------------- /pkg/KubeArmorHostPolicy/config/webhook/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - manifests.yaml 3 | - service.yaml 4 | 5 | configurations: 6 | - kustomizeconfig.yaml 7 | -------------------------------------------------------------------------------- /pkg/KubeArmorHostPolicy/config/webhook/kustomizeconfig.yaml: -------------------------------------------------------------------------------- 1 | # the following config is for teaching kustomize where to look at when substituting vars. 2 | # It requires kustomize v2.1.0 or newer to work properly. 3 | nameReference: 4 | - kind: Service 5 | version: v1 6 | fieldSpecs: 7 | - kind: MutatingWebhookConfiguration 8 | group: admissionregistration.k8s.io 9 | path: webhooks/clientConfig/service/name 10 | - kind: ValidatingWebhookConfiguration 11 | group: admissionregistration.k8s.io 12 | path: webhooks/clientConfig/service/name 13 | 14 | namespace: 15 | - kind: MutatingWebhookConfiguration 16 | group: admissionregistration.k8s.io 17 | path: webhooks/clientConfig/service/namespace 18 | create: true 19 | - kind: ValidatingWebhookConfiguration 20 | group: admissionregistration.k8s.io 21 | path: webhooks/clientConfig/service/namespace 22 | create: true 23 | 24 | varReference: 25 | - path: metadata/annotations 26 | -------------------------------------------------------------------------------- /pkg/KubeArmorHostPolicy/config/webhook/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: webhook-service 5 | namespace: system 6 | spec: 7 | ports: 8 | - port: 443 9 | targetPort: 9443 10 | selector: 11 | control-plane: controller-manager 12 | -------------------------------------------------------------------------------- /pkg/KubeArmorHostPolicy/controllers/kubearmorhostpolicy_controller.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2021 Authors of KubeArmor 3 | 4 | package controllers 5 | 6 | import ( 7 | "context" 8 | "fmt" 9 | 10 | "github.com/go-logr/logr" 11 | ctrl "sigs.k8s.io/controller-runtime" 12 | "sigs.k8s.io/controller-runtime/pkg/client" 13 | 14 | securityv1 "github.com/kubearmor/KubeArmor/pkg/KubeArmorHostPolicy/api/v1" 15 | "k8s.io/apimachinery/pkg/api/errors" 16 | "k8s.io/apimachinery/pkg/runtime" 17 | ) 18 | 19 | // KubeArmorHostPolicyReconciler reconciles a KubeArmorHostPolicy object 20 | type KubeArmorHostPolicyReconciler struct { 21 | client.Client 22 | Log logr.Logger 23 | Scheme *runtime.Scheme 24 | } 25 | 26 | // +kubebuilder:rbac:groups=security.kubearmor.com,resources=kubearmorhostpolicies,verbs=get;list;watch;create;update;patch;delete 27 | // +kubebuilder:rbac:groups=security.kubearmor.com,resources=kubearmorhostpolicies/status,verbs=get;update;patch 28 | 29 | func (r *KubeArmorHostPolicyReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) { 30 | ctx := context.Background() 31 | log := r.Log.WithValues("kubearmorhostpolicy", req.NamespacedName) 32 | 33 | policy := &securityv1.KubeArmorHostPolicy{} 34 | 35 | if err := r.Get(ctx, req.NamespacedName, policy); err != nil { 36 | if errors.IsNotFound(err) { 37 | return ctrl.Result{}, client.IgnoreNotFound(err) 38 | } 39 | return ctrl.Result{}, err 40 | } 41 | 42 | var policyErr error 43 | 44 | // Validate KubeArmorPolicy 45 | // if there are some issues in the policy the delete the policy and return failure code 46 | policyErr = validateProcessSchema(policy, req) 47 | if policyErr != nil { 48 | goto POLICYERROR 49 | } 50 | 51 | policyErr = validateFileSchema(policy, req) 52 | if policyErr != nil { 53 | goto POLICYERROR 54 | } 55 | 56 | policyErr = validateNetworkSchema(policy, req) 57 | if policyErr != nil { 58 | goto POLICYERROR 59 | } 60 | 61 | policyErr = validateCapabilitiesSchema(policy, req) 62 | if policyErr != nil { 63 | goto POLICYERROR 64 | } 65 | 66 | POLICYERROR: 67 | if policyErr != nil { 68 | // Update PolicyStatus 69 | policy.Status.PolicyStatus = "Not OK" 70 | err := r.Status().Update(ctx, policy) 71 | log.Info("Invalid KubeArmorHostPolicy") 72 | // delete the invalid KubeArmorPolicy 73 | // err := r.Delete(ctx, policy) 74 | return ctrl.Result{}, err 75 | } 76 | 77 | // Update PolicyStatus 78 | policy.Status.PolicyStatus = "OK" 79 | _ = r.Status().Update(ctx, policy) 80 | log.Info("Fetched KubeArmorHostPolicy") 81 | return ctrl.Result{}, nil 82 | } 83 | 84 | func (r *KubeArmorHostPolicyReconciler) SetupWithManager(mgr ctrl.Manager) error { 85 | return ctrl.NewControllerManagedBy(mgr). 86 | For(&securityv1.KubeArmorHostPolicy{}). 87 | Complete(r) 88 | } 89 | 90 | func validateProcessSchema(policy *securityv1.KubeArmorHostPolicy, req ctrl.Request) error { 91 | var policyErr error 92 | for _, matchPaths := range policy.Spec.Process.MatchPaths { 93 | if policy.Spec.Action != "Allow" { 94 | if matchPaths.OwnerOnly { 95 | policyErr = fmt.Errorf("ownerOnly works with the Allow action %v", req.NamespacedName) 96 | return policyErr 97 | } 98 | } 99 | for _, fromSource := range matchPaths.FromSource { 100 | if fromSource.Path != "" { 101 | if fromSource.Recursive || !fromSource.Recursive { 102 | policyErr = fmt.Errorf("recursive is only effective with directories, not paths %v", req.NamespacedName) 103 | return policyErr 104 | } 105 | } 106 | } 107 | } 108 | for _, matchDirectories := range policy.Spec.Process.MatchDirectories { 109 | if policy.Spec.Action != "Allow" { 110 | if matchDirectories.OwnerOnly { 111 | policyErr = fmt.Errorf("ownerOnly works with the Allow action %v", req.NamespacedName) 112 | return policyErr 113 | } 114 | } 115 | } 116 | for _, matchPatterns := range policy.Spec.Process.MatchPatterns { 117 | if policy.Spec.Action != "Allow" { 118 | if matchPatterns.OwnerOnly { 119 | policyErr = fmt.Errorf("ownerOnly works with the Allow action %v", req.NamespacedName) 120 | return policyErr 121 | } 122 | } 123 | } 124 | return policyErr 125 | } 126 | 127 | func validateFileSchema(policy *securityv1.KubeArmorHostPolicy, req ctrl.Request) error { 128 | var policyErr error 129 | for _, matchPaths := range policy.Spec.File.MatchPaths { 130 | if policy.Spec.Action != "Allow" { 131 | if matchPaths.OwnerOnly { 132 | policyErr = fmt.Errorf("ownerOnly works with the Allow action %v", req.NamespacedName) 133 | return policyErr 134 | } 135 | } 136 | for _, fromSource := range matchPaths.FromSource { 137 | if fromSource.Path != "" { 138 | if fromSource.Recursive { 139 | policyErr = fmt.Errorf("recursive is only effective with directories, not paths %v", req.NamespacedName) 140 | return policyErr 141 | } 142 | } 143 | } 144 | } 145 | for _, matchDirectories := range policy.Spec.File.MatchDirectories { 146 | if policy.Spec.Action != "Allow" { 147 | if matchDirectories.OwnerOnly { 148 | policyErr = fmt.Errorf("ownerOnly works with the Allow action %v", req.NamespacedName) 149 | return policyErr 150 | } 151 | } 152 | } 153 | for _, matchPatterns := range policy.Spec.File.MatchPatterns { 154 | if policy.Spec.Action != "Allow" { 155 | if matchPatterns.OwnerOnly { 156 | policyErr = fmt.Errorf("ownerOnly works with the Allow action %v", req.NamespacedName) 157 | return policyErr 158 | } 159 | } 160 | } 161 | return policyErr 162 | } 163 | 164 | func validateNetworkSchema(policy *securityv1.KubeArmorHostPolicy, req ctrl.Request) error { 165 | var policyErr error 166 | for _, matchProtocols := range policy.Spec.Network.MatchProtocols { 167 | for _, fromSource := range matchProtocols.FromSource { 168 | if fromSource.Path != "" { 169 | if fromSource.Recursive || !fromSource.Recursive { 170 | policyErr = fmt.Errorf("recursive is only effective with directories, not paths %v", req.NamespacedName) 171 | return policyErr 172 | } 173 | } 174 | } 175 | } 176 | return policyErr 177 | } 178 | 179 | func validateCapabilitiesSchema(policy *securityv1.KubeArmorHostPolicy, req ctrl.Request) error { 180 | var policyErr error 181 | for _, matchCapabilities := range policy.Spec.Capabilities.MatchCapabilities { 182 | for _, fromSource := range matchCapabilities.FromSource { 183 | if fromSource.Path != "" { 184 | if fromSource.Recursive || !fromSource.Recursive { 185 | policyErr = fmt.Errorf("recursive is only effective with directories, not paths %v", req.NamespacedName) 186 | return policyErr 187 | } 188 | } 189 | } 190 | } 191 | return policyErr 192 | } 193 | -------------------------------------------------------------------------------- /pkg/KubeArmorHostPolicy/controllers/suite_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2021 Authors of KubeArmor 3 | 4 | package controllers 5 | 6 | import ( 7 | "path/filepath" 8 | "testing" 9 | 10 | . "github.com/onsi/ginkgo" 11 | . "github.com/onsi/gomega" 12 | "sigs.k8s.io/controller-runtime/pkg/client" 13 | "sigs.k8s.io/controller-runtime/pkg/envtest" 14 | "sigs.k8s.io/controller-runtime/pkg/envtest/printer" 15 | logf "sigs.k8s.io/controller-runtime/pkg/log" 16 | "sigs.k8s.io/controller-runtime/pkg/log/zap" 17 | 18 | securityv1 "github.com/kubearmor/KubeArmor/pkg/KubeArmorHostPolicy/api/v1" 19 | "k8s.io/client-go/kubernetes/scheme" 20 | "k8s.io/client-go/rest" 21 | // +kubebuilder:scaffold:imports 22 | ) 23 | 24 | // These tests use Ginkgo (BDD-style Go testing framework). Refer to 25 | // http://onsi.github.io/ginkgo/ to learn more about Ginkgo. 26 | 27 | var cfg *rest.Config 28 | var k8sClient client.Client 29 | var testEnv *envtest.Environment 30 | 31 | func TestAPIs(t *testing.T) { 32 | RegisterFailHandler(Fail) 33 | 34 | RunSpecsWithDefaultAndCustomReporters(t, 35 | "Controller Suite", 36 | []Reporter{printer.NewlineReporter{}}) 37 | } 38 | 39 | var _ = BeforeSuite(func(done Done) { 40 | logf.SetLogger(zap.LoggerTo(GinkgoWriter, true)) 41 | 42 | By("bootstrapping test environment") 43 | testEnv = &envtest.Environment{ 44 | CRDDirectoryPaths: []string{filepath.Join("..", "config", "crd", "bases")}, 45 | } 46 | 47 | var err error 48 | cfg, err = testEnv.Start() 49 | Expect(err).ToNot(HaveOccurred()) 50 | Expect(cfg).ToNot(BeNil()) 51 | 52 | err = securityv1.AddToScheme(scheme.Scheme) 53 | Expect(err).NotTo(HaveOccurred()) 54 | 55 | // +kubebuilder:scaffold:scheme 56 | 57 | k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme}) 58 | Expect(err).ToNot(HaveOccurred()) 59 | Expect(k8sClient).ToNot(BeNil()) 60 | 61 | close(done) 62 | }, 60) 63 | 64 | var _ = AfterSuite(func() { 65 | By("tearing down the test environment") 66 | err := testEnv.Stop() 67 | Expect(err).ToNot(HaveOccurred()) 68 | }) 69 | -------------------------------------------------------------------------------- /pkg/KubeArmorHostPolicy/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/kubearmor/KubeArmor/pkg/KubeArmorHostPolicy 2 | 3 | go 1.13 4 | 5 | require ( 6 | github.com/go-logr/logr v0.1.0 7 | github.com/onsi/ginkgo v1.11.0 8 | github.com/onsi/gomega v1.8.1 9 | k8s.io/apimachinery v0.17.2 10 | k8s.io/client-go v0.17.2 11 | sigs.k8s.io/controller-runtime v0.5.0 12 | ) 13 | -------------------------------------------------------------------------------- /pkg/KubeArmorHostPolicy/hack/boilerplate.go.txt: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2021 Authors of KubeArmor 3 | -------------------------------------------------------------------------------- /pkg/KubeArmorHostPolicy/main.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2021 Authors of KubeArmor 3 | 4 | package main 5 | 6 | import ( 7 | "flag" 8 | "os" 9 | 10 | ctrl "sigs.k8s.io/controller-runtime" 11 | "sigs.k8s.io/controller-runtime/pkg/log/zap" 12 | 13 | "k8s.io/apimachinery/pkg/runtime" 14 | clientgoscheme "k8s.io/client-go/kubernetes/scheme" 15 | _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" 16 | 17 | securityv1 "github.com/kubearmor/KubeArmor/pkg/KubeArmorHostPolicy/api/v1" 18 | "github.com/kubearmor/KubeArmor/pkg/KubeArmorHostPolicy/controllers" 19 | // +kubebuilder:scaffold:imports 20 | ) 21 | 22 | var ( 23 | scheme = runtime.NewScheme() 24 | setupLog = ctrl.Log.WithName("setup") 25 | ) 26 | 27 | func init() { 28 | _ = clientgoscheme.AddToScheme(scheme) 29 | 30 | _ = securityv1.AddToScheme(scheme) 31 | // +kubebuilder:scaffold:scheme 32 | } 33 | 34 | func main() { 35 | var metricsAddr string 36 | var enableLeaderElection bool 37 | flag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.") 38 | flag.BoolVar(&enableLeaderElection, "enable-leader-election", false, 39 | "Enable leader election for controller manager. "+ 40 | "Enabling this will ensure there is only one active controller manager.") 41 | flag.Parse() 42 | 43 | ctrl.SetLogger(zap.New(zap.UseDevMode(true))) 44 | 45 | mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ 46 | Scheme: scheme, 47 | MetricsBindAddress: metricsAddr, 48 | Port: 9443, 49 | LeaderElection: enableLeaderElection, 50 | LeaderElectionID: "62bbde7f.kubearmor.com", 51 | }) 52 | if err != nil { 53 | setupLog.Error(err, "unable to start manager") 54 | os.Exit(1) 55 | } 56 | 57 | if err = (&controllers.KubeArmorHostPolicyReconciler{ 58 | Client: mgr.GetClient(), 59 | Log: ctrl.Log.WithName("controllers").WithName("KubeArmorHostPolicy"), 60 | Scheme: mgr.GetScheme(), 61 | }).SetupWithManager(mgr); err != nil { 62 | setupLog.Error(err, "unable to create controller", "controller", "KubeArmorHostPolicy") 63 | os.Exit(1) 64 | } 65 | // +kubebuilder:scaffold:builder 66 | 67 | setupLog.Info("starting manager") 68 | if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil { 69 | setupLog.Error(err, "problem running manager") 70 | os.Exit(1) 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /scripts/install-workload.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | #set -x 4 | shopt -s extglob 5 | 6 | if [ -z "$CLUSTER_ADDR" ] ; then 7 | echo "CLUSTER_ADDR must be defined to the IP:PORT at which the KVM Service is reachable." 8 | exit 1 9 | fi 10 | 11 | port='@(6553[0-5]|655[0-2][0-9]|65[0-4][0-9][0-9]|6[0-4][0-9][0-9][0-9]|[1-5][0-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9]|[1-9])' 12 | byte='@(25[0-5]|2[0-4][0-9]|[1][0-9][0-9]|[1-9][0-9]|[0-9])' 13 | ipv4="$byte\.$byte\.$byte\.$byte" 14 | 15 | # Default port is for a HostPort service 16 | case "$CLUSTER_ADDR" in 17 | \[+([0-9a-fA-F:])\]:$port) 18 | CLUSTER_PORT=${CLUSTER_ADDR##\[*\]:} 19 | CLUSTER_IP=${CLUSTER_ADDR#\[} 20 | CLUSTER_IP=${CLUSTER_IP%\]:*} 21 | ;; 22 | [^[]$ipv4:$port) 23 | CLUSTER_PORT=${CLUSTER_ADDR##*:} 24 | CLUSTER_IP=${CLUSTER_ADDR%:*} 25 | ;; 26 | *:*) 27 | echo "Malformed CLUSTER_ADDR: $CLUSTER_ADDR" 28 | exit 1 29 | ;; 30 | *) 31 | CLUSTER_PORT=12345 32 | CLUSTER_IP=$CLUSTER_ADDR 33 | ;; 34 | esac 35 | 36 | DOCKER_OPTS=" -d -p 32767:32767 --log-driver syslog --restart always" 37 | DOCKER_OPTS+=" --privileged --add-host kvms.kubearmor.io:$CLUSTER_IP" 38 | DOCKER_OPTS+=" --volume /var/run/docker.sock:/var/run/docker.sock" 39 | DOCKER_OPTS+=" --volume /usr/src:/usr/src" 40 | DOCKER_OPTS+=" --volume /lib/modules:/lib/modules" 41 | DOCKER_OPTS+=" --volume /sys/fs/bpf:/sys/fs/bpf" 42 | DOCKER_OPTS+=" --volume /sys/kernel/debug:/sys/kernel/debug" 43 | DOCKER_OPTS+=" --volume /etc/apparmor.d:/etc/apparmor.d" 44 | DOCKER_OPTS+=" --volume /etc/os-release:/media/root/etc/os-release" 45 | 46 | KUBEARMOR_OPTS="-gRPC=32767 -logPath=/tmp/kubearmor.log -enableKubeArmorHostPolicy" 47 | 48 | if [ -n "$(sudo docker ps -a -q -f name=kubearmor)" ]; then 49 | echo "Shutting down running kubearmor agent" 50 | sudo docker rm -f kubearmor || true 51 | fi 52 | 53 | KUBEARMOR_IMAGE="kubearmor/kubearmor:latest" 54 | 55 | echo "Launching kubearmor agent..." 56 | sudo docker run --name kubearmor $DOCKER_OPTS $KUBEARMOR_IMAGE kubearmor $KUBEARMOR_OPTS 57 | -------------------------------------------------------------------------------- /scripts/operator.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | DOCKER_OPTS=" -d -p 32769:32769 --log-driver syslog --restart always" 4 | DOCKER_OPTS+=" --privileged --add-host kvms.kvmoperator.io:1.1.1.1" 5 | DOCKER_OPTS+=" --volume /var/run/docker.sock:/var/run/docker.sock" 6 | DOCKER_OPTS+=" --volume /usr/src:/usr/src" 7 | DOCKER_OPTS+=" --volume /lib/modules:/lib/modules" 8 | DOCKER_OPTS+=" --volume /sys/kernel/debug:/sys/kernel/debug" 9 | DOCKER_OPTS+=" --volume /etc/kubernetes/pki/etcd/:/etc/kubernetes/pki/etcd/" 10 | DOCKER_OPTS+=" --volume /etc/os-release:/media/root/etc/os-release" 11 | 12 | kvmoperator_OPTS="-port=32769 -ipAddress=1.1.1.1" 13 | 14 | if [ -n "$(sudo docker ps -a -q -f name=kvmoperator)" ]; then 15 | echo "Shutting down running kvmoperator agent" 16 | sudo docker rm -f kvmoperator || true 17 | fi 18 | 19 | kvmoperator_IMAGE="quay.io/maddy007_maha/kvmoperator:v3" 20 | 21 | echo "Launching kvmoperator agent..." 22 | sudo docker run --name kvmoperator $DOCKER_OPTS $kvmoperator_IMAGE kvmoperator $kvmoperator_OPTS 23 | #sudo docker run --name kvmoperator -d -p 32769:32769 --log-driver syslog --restart always --volume /var/run/docker.sock:/var/run/docker.sock --volume /etc/kubernetes/pki/etcd/:/etc/kubernetes/pki/etcd/ --privileged $kvmoperator_IMAGE kvmoperator $kvmoperator_OPTS 24 | 25 | 26 | -------------------------------------------------------------------------------- /scripts/service.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | DOCKER_OPTS=" -d -p 32769:32769 --log-driver syslog --restart always" 4 | DOCKER_OPTS+=" --privileged --add-host kvms.kvmservice.io:1.1.1.1" 5 | DOCKER_OPTS+=" --volume /var/run/docker.sock:/var/run/docker.sock" 6 | DOCKER_OPTS+=" --volume /usr/src:/usr/src" 7 | DOCKER_OPTS+=" --volume /lib/modules:/lib/modules" 8 | DOCKER_OPTS+=" --volume /sys/fs/bpf:/sys/fs/bpf" 9 | DOCKER_OPTS+=" --volume /sys/kernel/debug:/sys/kernel/debug" 10 | DOCKER_OPTS+=" --volume /etc/os-release:/media/root/etc/os-release" 11 | 12 | kvmservice_OPTS="-port=32769 -ipAddress=1.1.1.1" 13 | 14 | if [ -n "$(sudo docker ps -a -q -f name=kvmservice)" ]; then 15 | echo "Shutting down running kvmservice agent" 16 | sudo docker rm -f kvmservice || true 17 | fi 18 | 19 | kvmservice_IMAGE="quay.io/maddy007_maha/kvmservice:v3" 20 | 21 | echo "Launching kvmservice agent..." 22 | #sudo docker run --name kvmservice $DOCKER_OPTS $kvmservice_IMAGE kvmservice $kvmservice_OPTS 23 | sudo docker run --name kvmservice -d -p 32769:32769 --log-driver syslog --restart always --volume /var/run/docker.sock:/var/run/docker.sock --volume /etc/kubernetes/pki/etcd/:/etc/kubernetes/pki/etcd/ --privileged $kvmservice_IMAGE kvmservice $kvmservice_OPTS 24 | 25 | 26 | -------------------------------------------------------------------------------- /setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | cluster_clean() { 5 | kubectl delete -f /home/vagrant/KVMService/KVMService/service/kvmservice.yaml 6 | 7 | kubectl delete -f /home/vagrant/KVMService/KVMService/operator/kvmsoperator.yaml 8 | 9 | CRDS=`kubectl get kew | awk '(NR>1)' |awk '{print $1}'` 10 | echo "MDEBUG: $CRDS" 11 | 12 | kubectl delete kew $CRDS 13 | 14 | KHPS=`kubectl get khp | awk '(NR>1)' |awk '{print $1}'` 15 | echo "MDEBUG:$KHPS" 16 | 17 | kubectl delete khp $KHPS 18 | 19 | sudo rm /mnt/gen-script/* 20 | 21 | kubectl get kew 22 | kubectl get khp 23 | } 24 | 25 | cluster_up() { 26 | kubectl apply -f /home/vagrant/KVMService/KVMService/service/kvmservice.yaml 27 | 28 | kubectl apply -f /home/vagrant/KVMService/KVMService/operator/kvmsoperator.yaml 29 | } 30 | 31 | if [ $# -eq 1 ]; then 32 | if [ $1 == "clean" ]; then 33 | echo "Cleaning the cluster" 34 | cluster_clean 35 | else 36 | echo "err: invalid commad" 37 | fi 38 | else 39 | echo "Bringing up the cluster" 40 | cluster_up 41 | fi 42 | -------------------------------------------------------------------------------- /src/common/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/kubearmor/KVMService/src/common 2 | 3 | go 1.17 4 | 5 | replace ( 6 | github.com/kubearmor/KVMService/src/constants => ../constants 7 | github.com/kubearmor/KVMService/src/log => ../log 8 | ) 9 | 10 | require ( 11 | github.com/kubearmor/KVMService/src/constants v0.0.0-00010101000000-000000000000 12 | github.com/kubearmor/KVMService/src/log v0.0.0-00010101000000-000000000000 13 | k8s.io/apimachinery v0.22.4 14 | k8s.io/client-go v0.22.4 15 | ) 16 | 17 | require ( 18 | github.com/davecgh/go-spew v1.1.1 // indirect 19 | github.com/go-logr/logr v0.4.0 // indirect 20 | github.com/gogo/protobuf v1.3.2 // indirect 21 | github.com/golang/protobuf v1.5.2 // indirect 22 | github.com/google/go-cmp v0.5.5 // indirect 23 | github.com/google/gofuzz v1.1.0 // indirect 24 | github.com/googleapis/gnostic v0.5.5 // indirect 25 | github.com/json-iterator/go v1.1.11 // indirect 26 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 27 | github.com/modern-go/reflect2 v1.0.1 // indirect 28 | go.uber.org/atomic v1.7.0 // indirect 29 | go.uber.org/multierr v1.6.0 // indirect 30 | go.uber.org/zap v1.19.1 // indirect 31 | golang.org/x/net v0.0.0-20210520170846-37e1c6afe023 // indirect 32 | golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect 33 | golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 // indirect 34 | golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d // indirect 35 | golang.org/x/text v0.3.6 // indirect 36 | golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect 37 | google.golang.org/appengine v1.6.5 // indirect 38 | google.golang.org/protobuf v1.26.0 // indirect 39 | gopkg.in/inf.v0 v0.9.1 // indirect 40 | gopkg.in/yaml.v2 v2.4.0 // indirect 41 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect 42 | k8s.io/api v0.22.4 // indirect 43 | k8s.io/klog/v2 v2.9.0 // indirect 44 | k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a // indirect 45 | sigs.k8s.io/structured-merge-diff/v4 v4.1.2 // indirect 46 | sigs.k8s.io/yaml v1.2.0 // indirect 47 | ) 48 | -------------------------------------------------------------------------------- /src/constants/constants.go: -------------------------------------------------------------------------------- 1 | package constants 2 | 3 | import "os" 4 | 5 | var ( 6 | KvmOprIdentityToEWName = "/kvm-opr-map-identity-to-ewname/" 7 | KvmOprEWNameToIdentity = "/kvm-opr-map-ewname-to-identity/" 8 | KvmOprLabelToIdentities = "/kvm-opr-label-to-identities-map/" 9 | KvmSvcIdentitiToPodIps = "/kvm-svc-identity-podip-maps/" 10 | KvmOprIdentityToLabel = "/kvm-opr-identity-to-label-maps/" 11 | 12 | KhpCRDName = "kubearmorhostpolicies" 13 | KewCRDName = "kubearmorexternalworkloads" 14 | LocalHostIPAddress = "127.0.0.1" 15 | KubeProxyK8sPort = "8001" 16 | KCLIPort = "32770" 17 | 18 | EtcdCertFile = "/etc/kubernetes/pki/etcd/server.crt" 19 | EtcdKeyFile = "/etc/kubernetes/pki/etcd/server.key" 20 | EtcdCAFile = "/etc/kubernetes/pki/etcd/ca.crt" 21 | EtcdEndPoints = "https://10.0.2.15:2379" 22 | EtcdClientTTL = 10 23 | 24 | EtcdServiceAccountName = "etcd0" 25 | KvmServiceAccountName = "kvmservice" 26 | KvmOperatorAccountName = "kvmsoperator" 27 | 28 | EtcdNamespace = os.Getenv("ETCD_NAMESPACE") 29 | KvmServiceNamespace = os.Getenv("KVMSERVICE_NAMESPACE") 30 | ) 31 | -------------------------------------------------------------------------------- /src/constants/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/kubearmor/KVMService/src/constants 2 | 3 | go 1.17 4 | -------------------------------------------------------------------------------- /src/etcd/etcdClient.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Authors of KubeArmor 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package etcdClient 5 | 6 | import ( 7 | "context" 8 | "time" 9 | 10 | kc "github.com/kubearmor/KVMService/src/common" 11 | ct "github.com/kubearmor/KVMService/src/constants" 12 | kg "github.com/kubearmor/KVMService/src/log" 13 | clientv3 "go.etcd.io/etcd/client/v3" 14 | ) 15 | 16 | type EtcdClient struct { 17 | etcdClient *clientv3.Client 18 | leaseResponse *clientv3.LeaseGrantResponse 19 | } 20 | 21 | func NewEtcdClient() *EtcdClient { 22 | /* TODO : To enable certificates in cluster and validate the same 23 | * Works fine with minikube 24 | tlsInfo := transport.TLSInfo{ 25 | CertFile: ct.EtcdCertFile, 26 | KeyFile: ct.EtcdKeyFile, 27 | TrustedCAFile: ct.EtcdCAFile, 28 | } 29 | tlsConfig, err := tlsInfo.ClientConfig() 30 | if err != nil { 31 | kg.Err(err.Error()) 32 | return nil 33 | } 34 | */ 35 | 36 | cli, err := clientv3.New(clientv3.Config{ 37 | Endpoints: []string{kc.GetEtcdEndPoint(ct.EtcdServiceAccountName)}, 38 | DialTimeout: 5 * time.Second, 39 | //TLS: tlsConfig, 40 | }) 41 | if err != nil { 42 | kg.Err(err.Error()) 43 | return nil 44 | } 45 | 46 | // minimum lease TTL is 5-second 47 | resp, err := cli.Grant(context.TODO(), int64(ct.EtcdClientTTL)) 48 | if err != nil { 49 | kg.Err(err.Error()) 50 | return nil 51 | } 52 | 53 | kg.Print("Initialized the ETCD client!") 54 | return &EtcdClient{etcdClient: cli, leaseResponse: resp} 55 | } 56 | 57 | func (cli *EtcdClient) EtcdPutWithTTL(ctx context.Context, key, value string) error { 58 | kg.Printf("ETCD: putting values with TTL key:%v value:%v\n", key, value) 59 | _, err := cli.etcdClient.Put(context.TODO(), key, value, clientv3.WithLease(cli.leaseResponse.ID)) 60 | if err != nil { 61 | kg.Err(err.Error()) 62 | return err 63 | } 64 | return nil 65 | } 66 | 67 | func (cli *EtcdClient) EtcdPut(ctx context.Context, key, value string) error { 68 | kg.Printf("ETCD: Putting values key:%v value:%v\n", key, value) 69 | _, err := cli.etcdClient.Put(ctx, key, value) 70 | if err != nil { 71 | kg.Err(err.Error()) 72 | return err 73 | } 74 | return nil 75 | } 76 | 77 | func (cli *EtcdClient) EtcdGetRaw(ctx context.Context, key string) (*clientv3.GetResponse, error) { 78 | kg.Printf("ETCD: Getting raw values key:%v\n", key) 79 | resp, err := cli.etcdClient.Get(ctx, key, clientv3.WithPrefix()) 80 | if err != nil { 81 | kg.Err(err.Error()) 82 | return nil, err 83 | } 84 | if len(resp.Kvs) == 0 { 85 | kg.Print("ETCD: err: No data") 86 | return nil, nil 87 | } 88 | 89 | return resp, nil 90 | } 91 | 92 | func (cli *EtcdClient) EtcdGet(ctx context.Context, key string) (map[string]string, error) { 93 | kg.Printf("ETCD: Getting values key:%v\n", key) 94 | keyValuePair := make(map[string]string) 95 | resp, err := cli.etcdClient.Get(ctx, key, clientv3.WithPrefix()) 96 | if err != nil { 97 | kg.Err(err.Error()) 98 | return nil, err 99 | } 100 | if len(resp.Kvs) == 0 { 101 | kg.Print("ETCD: err: No data") 102 | return nil, nil 103 | } 104 | 105 | for _, ev := range resp.Kvs { 106 | keyValuePair[string(ev.Key)] = string(ev.Value) 107 | kg.Printf("ETCD: Key:%s Value:%s", string(ev.Key), string(ev.Value)) 108 | } 109 | return keyValuePair, nil 110 | } 111 | 112 | func (cli *EtcdClient) EtcdDelete(ctx context.Context, key string) error { 113 | kg.Printf("ETCD: Deleting key:%v", key) 114 | _, err := cli.etcdClient.Delete(ctx, key, clientv3.WithPrefix()) 115 | if err != nil { 116 | kg.Err(err.Error()) 117 | return err 118 | } 119 | return nil 120 | } 121 | 122 | func (cli *EtcdClient) KeepAliveEtcdConnection() { 123 | for { 124 | _, kaerr := cli.etcdClient.KeepAlive(context.TODO(), cli.leaseResponse.ID) 125 | if kaerr != nil { 126 | kg.Err(kaerr.Error()) 127 | kg.Print("ETCD: etcd connection handshake failed") 128 | } 129 | time.Sleep(time.Second * 3) 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/etcd/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/kubearmor/KVMService/src/etcd 2 | 3 | go 1.17 4 | 5 | replace ( 6 | github.com/kubearmor/KVMService/src/common => ../common 7 | github.com/kubearmor/KVMService/src/constants => ../constants 8 | github.com/kubearmor/KVMService/src/log => ../log 9 | github.com/kubearmor/KVMService/src/types => ../types 10 | ) 11 | 12 | require ( 13 | github.com/kubearmor/KVMService/src/common v0.0.0-00010101000000-000000000000 14 | github.com/kubearmor/KVMService/src/constants v0.0.0-00010101000000-000000000000 15 | github.com/kubearmor/KVMService/src/log v0.0.0-00010101000000-000000000000 16 | go.etcd.io/etcd/client/v3 v3.5.1 17 | ) 18 | 19 | require ( 20 | github.com/coreos/go-semver v0.3.0 // indirect 21 | github.com/coreos/go-systemd/v22 v22.3.2 // indirect 22 | github.com/davecgh/go-spew v1.1.1 // indirect 23 | github.com/go-logr/logr v0.4.0 // indirect 24 | github.com/gogo/protobuf v1.3.2 // indirect 25 | github.com/golang/protobuf v1.5.2 // indirect 26 | github.com/google/go-cmp v0.5.5 // indirect 27 | github.com/google/gofuzz v1.1.0 // indirect 28 | github.com/googleapis/gnostic v0.5.5 // indirect 29 | github.com/json-iterator/go v1.1.11 // indirect 30 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 31 | github.com/modern-go/reflect2 v1.0.1 // indirect 32 | go.etcd.io/etcd/api/v3 v3.5.1 // indirect 33 | go.etcd.io/etcd/client/pkg/v3 v3.5.1 // indirect 34 | go.uber.org/atomic v1.7.0 // indirect 35 | go.uber.org/multierr v1.6.0 // indirect 36 | go.uber.org/zap v1.19.1 // indirect 37 | golang.org/x/net v0.0.0-20210520170846-37e1c6afe023 // indirect 38 | golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect 39 | golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 // indirect 40 | golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d // indirect 41 | golang.org/x/text v0.3.6 // indirect 42 | golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect 43 | google.golang.org/appengine v1.6.5 // indirect 44 | google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c // indirect 45 | google.golang.org/grpc v1.38.0 // indirect 46 | google.golang.org/protobuf v1.26.0 // indirect 47 | gopkg.in/inf.v0 v0.9.1 // indirect 48 | gopkg.in/yaml.v2 v2.4.0 // indirect 49 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect 50 | k8s.io/api v0.22.4 // indirect 51 | k8s.io/apimachinery v0.22.4 // indirect 52 | k8s.io/client-go v0.22.4 // indirect 53 | k8s.io/klog/v2 v2.9.0 // indirect 54 | k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a // indirect 55 | sigs.k8s.io/structured-merge-diff/v4 v4.1.2 // indirect 56 | sigs.k8s.io/yaml v1.2.0 // indirect 57 | ) 58 | -------------------------------------------------------------------------------- /src/log/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/kubearmor/KVMService/src/log 2 | 3 | go 1.17 4 | 5 | require go.uber.org/zap v1.19.1 6 | 7 | require ( 8 | go.uber.org/atomic v1.7.0 // indirect 9 | go.uber.org/multierr v1.6.0 // indirect 10 | ) 11 | -------------------------------------------------------------------------------- /src/log/go.sum: -------------------------------------------------------------------------------- 1 | github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= 2 | github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= 3 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 4 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 5 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 6 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 7 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 8 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 9 | github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= 10 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 11 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 12 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 13 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 14 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 15 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= 16 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 17 | github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= 18 | go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= 19 | go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= 20 | go.uber.org/goleak v1.1.11-0.20210813005559-691160354723 h1:sHOAIxRGBp443oHZIPB+HsUGaksVCXVQENPxwTfQdH4= 21 | go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= 22 | go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= 23 | go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= 24 | go.uber.org/zap v1.19.1 h1:ue41HOKd1vGURxrmeKIgELGb3jPW9DMUDGtsinblHwI= 25 | go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= 26 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 27 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 28 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 29 | golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 30 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 31 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 32 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 33 | golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= 34 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 35 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 36 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 37 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 38 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 39 | golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 40 | golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 41 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 42 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 43 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 44 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 45 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 46 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 47 | golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 48 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 49 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 50 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 51 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 52 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 53 | gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= 54 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 55 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 56 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= 57 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 58 | -------------------------------------------------------------------------------- /src/log/logger.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2021 Authors of KubeArmor 3 | 4 | package log 5 | 6 | import ( 7 | "encoding/json" 8 | "time" 9 | 10 | "go.uber.org/zap" 11 | "go.uber.org/zap/zapcore" 12 | ) 13 | 14 | // ============ // 15 | // == Logger == // 16 | // ============ // 17 | 18 | // zapLogger Handler 19 | var zapLogger *zap.SugaredLogger 20 | 21 | // init Function 22 | func init() { 23 | initLogger() 24 | } 25 | 26 | // customTimeEncoder Function 27 | func customTimeEncoder(t time.Time, enc zapcore.PrimitiveArrayEncoder) { 28 | enc.AppendString(t.Format("2006-01-02 15:04:05.000000")) 29 | } 30 | 31 | // initLogger Function 32 | func initLogger() { 33 | defaultConfig := []byte(`{ 34 | "level": "debug", 35 | "encoding": "console", 36 | "outputPaths": ["stdout"], 37 | "encoderConfig": { 38 | "messageKey": "message", 39 | "levelKey": "level", 40 | "nameKey": "logger", 41 | "timeKey": "time", 42 | "callerKey": "logger", 43 | "stacktraceKey": "stacktrace", 44 | "callstackKey": "callstack", 45 | "errorKey": "error", 46 | "levelEncoder": "capitalColor", 47 | "durationEncoder": "second", 48 | "sampling": { 49 | "initial": "3", 50 | "thereafter": "10" 51 | } 52 | } 53 | }`) 54 | 55 | config := zap.Config{} 56 | if err := json.Unmarshal(defaultConfig, &config); err != nil { 57 | panic(err) 58 | } 59 | 60 | config.EncoderConfig.EncodeTime = customTimeEncoder 61 | config.Level.SetLevel(zap.DebugLevel) // if we need to set log level 62 | 63 | logger, err := config.Build() 64 | if err != nil { 65 | panic(err) 66 | } 67 | 68 | zapLogger = logger.Sugar() 69 | } 70 | 71 | // ======================= // 72 | // == Logging Functions == // 73 | // ======================= // 74 | 75 | // Print Function 76 | func Print(message string) { 77 | zapLogger.Info(message) 78 | } 79 | 80 | // Printf Function 81 | func Printf(message string, args ...interface{}) { 82 | zapLogger.Infof(message, args...) 83 | } 84 | 85 | // Debug Function 86 | func Debug(message string) { 87 | zapLogger.Debug(message) 88 | } 89 | 90 | // Debugf Function 91 | func Debugf(message string, args ...interface{}) { 92 | zapLogger.Debugf(message, args...) 93 | } 94 | 95 | // Err Function 96 | func Err(message string) { 97 | zapLogger.Error(message) 98 | } 99 | 100 | // Errf Function 101 | func Errf(message string, args ...interface{}) { 102 | zapLogger.Errorf(message, args...) 103 | } 104 | -------------------------------------------------------------------------------- /src/operator/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Authors of kvms-operator 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | CURDIR := $(shell pwd) 5 | CONTRIBDIR := $(realpath $(CURDIR)/../contribution) 6 | GO_EXEC := $(shell which go) 7 | LOGNAME := $(shell logname) 8 | NETNEXT := 1 9 | DLV_EXEC = $(GOPATH)/bin/dlv 10 | DLV_LPORT := 2345 11 | DLV_RPORT := $(shell expr $(DLV_LPORT) + $(NETNEXT)) 12 | KVMSOPERATOR_PID = $(shell pgrep kvms-operator) 13 | 14 | .PHONY: build 15 | build: 16 | cd $(CURDIR); go mod tidy 17 | cd $(CURDIR); go build -o kvms-operator main.go 18 | 19 | .PHONY: build-test 20 | build-test: 21 | cd $(CURDIR); go mod tidy 22 | cd $(CURDIR); sudo -E $(GO_EXEC) test -covermode=atomic -coverpkg=./... -c . -o kvms-operator 23 | 24 | .PHONY: run 25 | run: build 26 | cd $(CURDIR); sudo rm -f /tmp/kvms-operator.log 27 | cd $(CURDIR); sudo -E ./kvms-operator #-logPath=/tmp/kvms-operator.log 28 | 29 | .PHONY: run-per-pod 30 | run-per-pod: build 31 | cd $(CURDIR); sudo rm -f /tmp/kvms-operator.log 32 | cd $(CURDIR); sudo -E ./kvms-operator #-logPath=/tmp/kvms-operator.log -enableEnforcerPerPod 33 | 34 | .PHONY: run-with-host 35 | run-with-host: build 36 | cd $(CURDIR); sudo rm -f /tmp/kvms-operator.log 37 | cd $(CURDIR); sudo -E ./kvms-operator #-logPath=/tmp/kvms-operator.log -enableHostPolicy -enableExternalWorkloadPolicy 38 | 39 | .PHONY: test 40 | test: 41 | cd $(CURDIR)/feeder; go mod tidy 42 | cd $(CURDIR)/feeder; go clean -testcache .; go test -v . 43 | 44 | .PHONY: testall 45 | testall: 46 | cd $(CURDIR)/feeder; go mod tidy 47 | cd $(CURDIR)/feeder; go clean -testcache .; go test -v -coverprofile=.coverprofile . 48 | cd $(CURDIR)/enforcer; go mod tidy 49 | cd $(CURDIR)/enforcer; go clean -testcache .; sudo -E $(GO_EXEC) test -v -coverprofile=.coverprofile . 50 | cd $(CURDIR)/monitor; go mod tidy 51 | cd $(CURDIR)/monitor; go clean -testcache .; sudo -E $(GO_EXEC) test -v -coverprofile=.coverprofile . 52 | 53 | .PHONY: gofmt 54 | gofmt: 55 | cd $(CURDIR); gofmt -s -d $(shell find . -type f -name '*.go' -print) 56 | 57 | .PHONY: golint 58 | golint: 59 | ifeq (, $(shell which golint)) 60 | @{ \ 61 | set -e ;\ 62 | GOLINT_TMP_DIR=$$(mktemp -d) ;\ 63 | cd $$GOLINT_TMP_DIR ;\ 64 | go mod init tmp ;\ 65 | go get -u golang.org/x/lint/golint ;\ 66 | rm -rf $$GOLINT_TMP_DIR ;\ 67 | } 68 | endif 69 | cd $(CURDIR); golint ./... 70 | 71 | .PHONY: gosec 72 | gosec: 73 | ifeq (, $(shell which gosec)) 74 | @{ \ 75 | set -e ;\ 76 | GOSEC_TMP_DIR=$$(mktemp -d) ;\ 77 | cd $$GOSEC_TMP_DIR ;\ 78 | go mod init tmp ;\ 79 | go get -u github.com/securego/gosec/v2/cmd/gosec ;\ 80 | rm -rf $$GOSEC_TMP_DIR ;\ 81 | } 82 | endif 83 | cd $(CURDIR); gosec ./... 84 | 85 | .PHONY: clean 86 | clean: 87 | cd $(CURDIR); sudo rm -f kvms-operator /tmp/kvms-operator.log 88 | cd $(CURDIR); find . -name .coverprofile | xargs -I {} rm {} 89 | $(CURDIR)/build/clean_source_files.sh 90 | 91 | .PHONY: vagrant-check 92 | vagrant-check: 93 | ifeq ($(LOGNAME), vagrant) 94 | $(error rule must be called from outside the vagrant environment) 95 | endif 96 | 97 | .PHONY: vagrant-up 98 | vagrant-up: vagrant-check 99 | cd $(CONTRIBDIR)/vagrant; NETNEXT=$(NETNEXT) DLV_RPORT=$(DLV_RPORT) vagrant up; true 100 | 101 | .PHONY: vagrant-status 102 | vagrant-status: vagrant-check 103 | cd $(CONTRIBDIR)/vagrant; NETNEXT=$(NETNEXT) DLV_RPORT=$(DLV_RPORT) vagrant status; true 104 | 105 | .PHONY: vagrant-reload 106 | vagrant-reload: vagrant-check 107 | cd $(CONTRIBDIR)/vagrant; NETNEXT=$(NETNEXT) DLV_RPORT=$(DLV_RPORT) vagrant reload; true 108 | 109 | .PHONY: vagrant-ssh 110 | vagrant-ssh: vagrant-check 111 | cd $(CONTRIBDIR)/vagrant; NETNEXT=$(NETNEXT) DLV_RPORT=$(DLV_RPORT) vagrant ssh; true 112 | 113 | .PHONY: vagrant-halt 114 | vagrant-halt: vagrant-check 115 | cd $(CONTRIBDIR)/vagrant; NETNEXT=$(NETNEXT) DLV_RPORT=$(DLV_RPORT) vagrant halt; true 116 | 117 | .PHONY: vagrant-destroy 118 | vagrant-destroy: vagrant-check 119 | cd $(CONTRIBDIR)/vagrant; NETNEXT=$(NETNEXT) DLV_RPORT=$(DLV_RPORT) vagrant destroy; true 120 | 121 | $(DLV_EXEC): 122 | go get -u github.com/go-delve/delve/cmd/dlv 123 | 124 | .PHONY: debug-attach 125 | debug-attach: $(DLV_EXEC) 126 | ifeq ($(KVMSOPERATOR_PID), ) 127 | $(error kvms-operator must be running - execute 'make run' first) 128 | endif 129 | sudo $(DLV_EXEC) attach $(KVMSOPERATOR_PID) --headless -l=:$(DLV_LPORT) --log --api-version 2 $(CURDIR) 130 | -------------------------------------------------------------------------------- /src/operator/build/Dockerfile.kvmsoperator: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | # Copyright 2021 Authors of KVMSOperator 3 | 4 | ### Builder 5 | 6 | FROM golang:1.17.1-alpine3.14 as builder 7 | 8 | RUN apk update 9 | RUN apk add --no-cache bash git wget python3 linux-headers build-base clang clang-dev libc-dev bcc-dev 10 | 11 | WORKDIR /usr/src/KVMSOperator 12 | 13 | COPY ./KVMSOperator ./KVMSOperator 14 | 15 | WORKDIR /usr/src/KVMSOperator/KVMSOperator/operator 16 | 17 | RUN ./patch.sh 18 | RUN GOOS=linux GOARCH=amd64 go build -a -ldflags '-s -w' -o kvmsoperator main.go 19 | 20 | ### Make executable image 21 | 22 | FROM alpine:3.14 23 | 24 | RUN apk update 25 | RUN echo "@community http://dl-cdn.alpinelinux.org/alpine/edge/community" | tee -a /etc/apk/repositories 26 | RUN echo "@testing http://dl-cdn.alpinelinux.org/alpine/edge/testing" | tee -a /etc/apk/repositories 27 | 28 | RUN apk update 29 | RUN apk add bash curl procps bcc@community bcc-dev@community 30 | RUN apk add apparmor@community apparmor-utils@community kubectl@testing 31 | 32 | COPY --from=builder /usr/src/KVMSOperator/KVMSOperator/operator/kvmsoperator /KVMSOperator/kvmsoperator 33 | 34 | ENTRYPOINT ["/KVMSOperator/kvmsoperator"] 35 | -------------------------------------------------------------------------------- /src/operator/build/Makefile: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | # Copyright 2021 Authors of KubeArmor 3 | 4 | CURDIR=$(shell pwd) 5 | 6 | .PHONY: build 7 | build: 8 | $(CURDIR)/build_kvmoperator.sh 9 | #$(CURDIR)/push_kubearmor.sh 10 | -------------------------------------------------------------------------------- /src/operator/build/build_kvmoperator.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # SPDX-License-Identifier: Apache-2.0 3 | # Copyright 2021 Authors of KVMSOperator 4 | 5 | realpath() { 6 | CURR=$PWD 7 | 8 | cd "$(dirname "$0")" 9 | LINK=$(readlink "$(basename "$0")") 10 | 11 | while [ "$LINK" ]; do 12 | cd "$(dirname "$LINK")" 13 | LINK=$(readlink "$(basename "$1")") 14 | done 15 | 16 | REALPATH="$PWD/$(basename "$1")" 17 | echo "$REALPATH" 18 | 19 | cd $CURR 20 | } 21 | 22 | ARMOR_HOME=`dirname $(realpath "$0")`/.. 23 | cd $ARMOR_HOME/build 24 | 25 | VERSION=latest 26 | 27 | # check version 28 | if [ ! -z $1 ]; then 29 | VERSION=$1 30 | fi 31 | 32 | # remove old images 33 | docker images | grep kvmsoperator | awk '{print $3}' | xargs -I {} docker rmi -f {} 2> /dev/null 34 | 35 | echo "[INFO] Removed existing kubearmor/kvmsoperator images" 36 | 37 | # remove old files (just in case) 38 | $ARMOR_HOME/build/clean_source_files.sh 39 | 40 | echo "[INFO] Removed existing source files" 41 | 42 | # copy files to build 43 | $ARMOR_HOME/build/copy_source_files.sh 44 | 45 | echo "[INFO] Copied new source files" 46 | 47 | # build a new image 48 | echo "[INFO] Building kubearmor/kvmsoperator:$VERSION" 49 | docker build -t kubearmor/kvmsoperator:$VERSION . -f $ARMOR_HOME/build/Dockerfile.kvmsoperator 50 | 51 | if [ $? != 0 ]; then 52 | echo "[FAILED] Failed to build kubearmor/kvmsoperator:$VERSION" 53 | exit 1 54 | else 55 | echo "[PASSED] Built kubearmor/kvmsoperator:$VERSION" 56 | fi 57 | 58 | # remove copied files 59 | $ARMOR_HOME/build/clean_source_files.sh 60 | 61 | echo "[INFO] Removed source files" 62 | exit 0 63 | -------------------------------------------------------------------------------- /src/operator/build/clean_source_files.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # SPDX-License-Identifier: Apache-2.0 3 | # Copyright 2021 Authors of KVMSOperator 4 | 5 | realpath() { 6 | CURR=$PWD 7 | 8 | cd "$(dirname "$0")" 9 | LINK=$(readlink "$(basename "$0")") 10 | 11 | while [ "$LINK" ]; do 12 | cd "$(dirname "$LINK")" 13 | LINK=$(readlink "$(basename "$1")") 14 | done 15 | 16 | REALPATH="$PWD/$(basename "$1")" 17 | echo "$REALPATH" 18 | 19 | cd $CURR 20 | } 21 | 22 | ARMOR_HOME=`dirname $(realpath "$0")`/.. 23 | 24 | rm -rf $ARMOR_HOME/build/KVMSOperator 25 | -------------------------------------------------------------------------------- /src/operator/build/copy_source_files.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # SPDX-License-Identifier: Apache-2.0 3 | # Copyright 2021 Authors of KVMSOperator 4 | 5 | realpath() { 6 | CURR=$PWD 7 | 8 | cd "$(dirname "$0")" 9 | LINK=$(readlink "$(basename "$0")") 10 | 11 | while [ "$LINK" ]; do 12 | cd "$(dirname "$LINK")" 13 | LINK=$(readlink "$(basename "$1")") 14 | done 15 | 16 | REALPATH="$PWD/$(basename "$1")" 17 | echo "$REALPATH" 18 | 19 | cd $CURR 20 | } 21 | 22 | ARMOR_HOME=`dirname $(realpath "$0")`/.. 23 | SERVICE_PATH=`dirname $(realpath "$0")`/.. 24 | 25 | mkdir -p $ARMOR_HOME/build/KVMSOperator 26 | mkdir -p $ARMOR_HOME/build/KVMSOperator/operator 27 | 28 | # copy files to build 29 | cp -r $SERVICE_PATH/../common/ $ARMOR_HOME/build/KVMSOperator/ 30 | cp -r $SERVICE_PATH/../log/ $ARMOR_HOME/build/KVMSOperator/ 31 | cp -r $SERVICE_PATH/../types/ $ARMOR_HOME/build/KVMSOperator/ 32 | cp -r $SERVICE_PATH/../etcd/ $ARMOR_HOME/build/KVMSOperator/ 33 | cp -r $SERVICE_PATH/../constants/ $ARMOR_HOME/build/KVMSOperator/ 34 | cp -r $SERVICE_PATH/core/ $ARMOR_HOME/build/KVMSOperator/operator 35 | cp $SERVICE_PATH/go.mod $ARMOR_HOME/build/KVMSOperator/operator 36 | cp $SERVICE_PATH/go.sum $ARMOR_HOME/build/KVMSOperator/operator 37 | cp $SERVICE_PATH/main.go $ARMOR_HOME/build/KVMSOperator/operator 38 | 39 | cp $SERVICE_PATH/build/patch.sh $ARMOR_HOME/build/KVMSOperator/operator 40 | cp $SERVICE_PATH/build/patch_selinux.sh $ARMOR_HOME/build/KVMSOperator/operator 41 | -------------------------------------------------------------------------------- /src/operator/build/patch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # SPDX-License-Identifier: Apache-2.0 3 | # Copyright 2021 Authors of KubeArmor 4 | 5 | # download gobpf 6 | go get -u github.com/iovisor/gobpf 7 | 8 | # fix module.go 9 | for GOBPF in $(ls $GOPATH/pkg/mod/github.com/iovisor); 10 | do 11 | echo $GOBPF 12 | sed -i 's/C.bpf_attach_uprobe(C.int(fd), attachType, evNameCS, binaryPathCS, (C.uint64_t)(addr), (C.pid_t)(pid), 0)/C.bpf_attach_uprobe(C.int(fd), attachType, evNameCS, binaryPathCS, (C.uint64_t)(addr), (C.pid_t)(pid))/g' $GOPATH/pkg/mod/github.com/iovisor/$GOBPF/bcc/module.go 13 | done 14 | -------------------------------------------------------------------------------- /src/operator/build/patch_selinux.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # SPDX-License-Identifier: Apache-2.0 3 | # Copyright 2021 Authors of KubeArmor 4 | 5 | # download gobpf 6 | go get -u github.com/iovisor/gobpf 7 | 8 | # fix module.go 9 | for GOBPF in $(ls $GOPATH/pkg/mod/github.com/iovisor); 10 | do 11 | echo $GOBPF 12 | sed -i 's/C.bpf_attach_uprobe(C.int(fd), attachType, evNameCS, binaryPathCS, (C.uint64_t)(addr), (C.pid_t)(pid), 0)/C.bpf_attach_uprobe(C.int(fd), attachType, evNameCS, binaryPathCS, (C.uint64_t)(addr), (C.pid_t)(pid))/g' $GOPATH/pkg/mod/github.com/iovisor/$GOBPF/bcc/module.go 13 | sed -i "s/C.bpf_module_create_c_from_string(cs, 2, (\*\*C.char)(\&cflagsC\[0\]), C.int(len(cflagsC)), (C.bool)(true), nil)/C.bpf_module_create_c_from_string(cs, 2, (\*\*C.char)(\&cflagsC\[0\]), C.int(len(cflagsC)), (C.bool)(true))/g" $GOPATH/pkg/mod/github.com/iovisor/$GOBPF/bcc/module.go 14 | sed -i 's/C.bcc_func_load(bpf.p, C.int(uint32(progType)), nameCS, start, size, license, version, C.int(logLevel), logBufP, C.uint(len(logBuf)), nil)/C.bcc_func_load(bpf.p, C.int(uint32(progType)), nameCS, start, size, license, version, C.int(logLevel), logBufP, C.uint(len(logBuf)))/g' $GOPATH/pkg/mod/github.com/iovisor/$GOBPF/bcc/module.go 15 | done 16 | -------------------------------------------------------------------------------- /src/operator/core/kvmOperator.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2021 Authors of KubeArmor 3 | 4 | package core 5 | 6 | import ( 7 | "context" 8 | "os" 9 | "os/signal" 10 | "sync" 11 | "syscall" 12 | "time" 13 | 14 | ct "github.com/kubearmor/KVMService/src/constants" 15 | etcd "github.com/kubearmor/KVMService/src/etcd" 16 | kg "github.com/kubearmor/KVMService/src/log" 17 | tp "github.com/kubearmor/KVMService/src/types" 18 | "google.golang.org/grpc" 19 | ) 20 | 21 | // ClientConn is the wrapper for a grpc client conn 22 | type ClientConn struct { 23 | *grpc.ClientConn 24 | unhealthy bool 25 | } 26 | 27 | // ====================== // 28 | // == KubeArmor Daemon == // 29 | // ====================== // 30 | 31 | // StopChan Channel 32 | var StopChan chan struct{} 33 | 34 | // init Function 35 | func init() { 36 | StopChan = make(chan struct{}) 37 | } 38 | 39 | // KVMSOperator Structure 40 | type KVMSOperator struct { 41 | EtcdClient *etcd.EtcdClient 42 | 43 | EnableExternalWorkloadPolicy bool 44 | 45 | // External workload policies and mappers 46 | ExternalWorkloadSecurityPolicies []tp.ExternalWorkloadSecurityPolicy 47 | ExternalWorkloadSecurityPoliciesLock *sync.RWMutex 48 | 49 | MapIdentityToEWName map[uint16]string 50 | MapEWNameToIdentity map[string]uint16 51 | 52 | MapIdentityToLabel map[uint16]string 53 | MapLabelToIdentities map[string][]uint16 54 | MapExternalWorkloadConnIdentity map[uint16]ClientConn 55 | 56 | // WgOperatorDaemon Handler 57 | WgOperatorDaemon sync.WaitGroup 58 | } 59 | 60 | // NewKVMSOperatorDaemon Function 61 | func NewKVMSOperatorDaemon() *KVMSOperator { 62 | dm := new(KVMSOperator) 63 | 64 | dm.EtcdClient = etcd.NewEtcdClient() 65 | 66 | dm.ExternalWorkloadSecurityPoliciesLock = new(sync.RWMutex) 67 | 68 | dm.MapIdentityToLabel = make(map[uint16]string) 69 | dm.MapLabelToIdentities = make(map[string][]uint16) 70 | 71 | dm.MapIdentityToEWName = make(map[uint16]string) 72 | dm.MapEWNameToIdentity = make(map[string]uint16) 73 | 74 | dm.MapExternalWorkloadConnIdentity = make(map[uint16]ClientConn) 75 | 76 | dm.WgOperatorDaemon = sync.WaitGroup{} 77 | kg.Print("Successfully initialized KVMSOperator") 78 | 79 | return dm 80 | } 81 | 82 | // DestroyKVMSOperator Function 83 | func (dm *KVMSOperator) DestroyKVMSOperator() { 84 | 85 | // wait for a while 86 | time.Sleep(time.Second * 1) 87 | 88 | // wait for other routines 89 | kg.Print("Waiting for remaining routine terminations") 90 | 91 | kg.Print("Deleting the external worklaods keys from etcd") 92 | dm.EtcdClient.EtcdDelete(context.TODO(), ct.KvmOprLabelToIdentities) 93 | 94 | dm.WgOperatorDaemon.Wait() 95 | } 96 | 97 | // ==================== // 98 | // == Signal Handler == // 99 | // ==================== // 100 | 101 | // GetOSSigChannel Function 102 | func GetOSSigChannel() chan os.Signal { 103 | c := make(chan os.Signal, 1) 104 | 105 | signal.Notify(c, 106 | syscall.SIGHUP, 107 | syscall.SIGINT, 108 | syscall.SIGTERM, 109 | syscall.SIGQUIT, 110 | os.Interrupt) 111 | 112 | return c 113 | } 114 | 115 | // ========== // 116 | // == Main == // 117 | // ========== // 118 | 119 | // KVMSService Function 120 | func KVMSOperatorDaemon() { 121 | 122 | // create a daemon 123 | dm := NewKVMSOperatorDaemon() 124 | 125 | // wait for a while 126 | time.Sleep(time.Second * 1) 127 | 128 | if K8s.InitK8sClient() { 129 | kg.Print("Started the external workload CRD watcher") 130 | go dm.WatchExternalWorkloadSecurityPolicies() 131 | 132 | } else { 133 | kg.Print("Kubernetes is not initiliased and Operator is failed!") 134 | } 135 | 136 | // wait for a while 137 | time.Sleep(time.Second * 1) 138 | 139 | // listen for interrupt signals 140 | sigChan := GetOSSigChannel() 141 | <-sigChan 142 | close(StopChan) 143 | 144 | // destroy the daemon 145 | dm.DestroyKVMSOperator() 146 | } 147 | -------------------------------------------------------------------------------- /src/operator/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/kubearmor/KVMService/src/operator 2 | 3 | go 1.17 4 | 5 | replace ( 6 | github.com/kubearmor/KVMService/src/common => ../common 7 | github.com/kubearmor/KVMService/src/constants => ../constants 8 | github.com/kubearmor/KVMService/src/etcd => ../etcd 9 | github.com/kubearmor/KVMService/src/log => ../log 10 | github.com/kubearmor/KVMService/src/types => ../types 11 | ) 12 | 13 | require ( 14 | github.com/kubearmor/KVMService/src/common v0.0.0-00010101000000-000000000000 15 | github.com/kubearmor/KVMService/src/constants v0.0.0-00010101000000-000000000000 16 | github.com/kubearmor/KVMService/src/etcd v0.0.0-00010101000000-000000000000 17 | github.com/kubearmor/KVMService/src/log v0.0.0-00010101000000-000000000000 18 | github.com/kubearmor/KVMService/src/types v0.0.0-00010101000000-000000000000 19 | google.golang.org/grpc v1.42.0 20 | k8s.io/apimachinery v0.22.4 21 | k8s.io/client-go v0.22.4 22 | ) 23 | 24 | require ( 25 | github.com/coreos/go-semver v0.3.0 // indirect 26 | github.com/coreos/go-systemd/v22 v22.3.2 // indirect 27 | github.com/davecgh/go-spew v1.1.1 // indirect 28 | github.com/go-logr/logr v0.4.0 // indirect 29 | github.com/gogo/protobuf v1.3.2 // indirect 30 | github.com/golang/protobuf v1.5.2 // indirect 31 | github.com/google/go-cmp v0.5.5 // indirect 32 | github.com/google/gofuzz v1.1.0 // indirect 33 | github.com/googleapis/gnostic v0.5.5 // indirect 34 | github.com/imdario/mergo v0.3.5 // indirect 35 | github.com/json-iterator/go v1.1.11 // indirect 36 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 37 | github.com/modern-go/reflect2 v1.0.1 // indirect 38 | github.com/spf13/pflag v1.0.5 // indirect 39 | go.etcd.io/etcd/api/v3 v3.5.1 // indirect 40 | go.etcd.io/etcd/client/pkg/v3 v3.5.1 // indirect 41 | go.etcd.io/etcd/client/v3 v3.5.1 // indirect 42 | go.uber.org/atomic v1.7.0 // indirect 43 | go.uber.org/multierr v1.6.0 // indirect 44 | go.uber.org/zap v1.19.1 // indirect 45 | golang.org/x/net v0.0.0-20210520170846-37e1c6afe023 // indirect 46 | golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect 47 | golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 // indirect 48 | golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d // indirect 49 | golang.org/x/text v0.3.6 // indirect 50 | golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect 51 | google.golang.org/appengine v1.6.5 // indirect 52 | google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c // indirect 53 | google.golang.org/protobuf v1.26.0 // indirect 54 | gopkg.in/inf.v0 v0.9.1 // indirect 55 | gopkg.in/yaml.v2 v2.4.0 // indirect 56 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect 57 | k8s.io/api v0.22.4 // indirect 58 | k8s.io/klog/v2 v2.9.0 // indirect 59 | k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a // indirect 60 | sigs.k8s.io/structured-merge-diff/v4 v4.1.2 // indirect 61 | sigs.k8s.io/yaml v1.2.0 // indirect 62 | ) 63 | -------------------------------------------------------------------------------- /src/operator/kvmsoperator.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: kvmsoperator 5 | namespace: kube-system 6 | --- 7 | apiVersion: rbac.authorization.k8s.io/v1 8 | kind: ClusterRoleBinding 9 | metadata: 10 | name: kvmsoperator 11 | roleRef: 12 | apiGroup: rbac.authorization.k8s.io 13 | kind: ClusterRole 14 | name: cluster-admin 15 | subjects: 16 | - kind: ServiceAccount 17 | name: kvmsoperator 18 | namespace: kube-system 19 | --- 20 | apiVersion: v1 21 | kind: Service 22 | metadata: 23 | name: kvmsoperator 24 | namespace: kube-system 25 | spec: 26 | selector: 27 | kvmsoperator-app: kvmsoperator 28 | ports: 29 | - port: 40400 30 | --- 31 | apiVersion: apps/v1 32 | kind: Deployment 33 | metadata: 34 | name: kvmsoperator 35 | namespace: kube-system 36 | labels: 37 | kvmsoperator-app: kvmsoperator 38 | spec: 39 | selector: 40 | matchLabels: 41 | kvmsoperator-app: kvmsoperator 42 | template: 43 | metadata: 44 | labels: 45 | kvmsoperator-app: kvmsoperator 46 | annotations: 47 | container.apparmor.security.beta.kubernetes.io/kvmsoperator: unconfined 48 | spec: 49 | serviceAccountName: kvmsoperator 50 | nodeSelector: 51 | kubernetes.io/os: linux 52 | tolerations: 53 | - operator: Exists 54 | hostPID: true 55 | hostNetwork: true 56 | restartPolicy: Always 57 | dnsPolicy: ClusterFirstWithHostNet 58 | containers: 59 | - name: kvmsoperator 60 | image: kubearmor/kvmsoperator:latest 61 | imagePullPolicy: Always 62 | securityContext: 63 | privileged: true 64 | env: 65 | - name: ETCD_NAMESPACE 66 | value: "kube-system" 67 | volumeMounts: 68 | - name: docker-sock-path # docker (read-only) 69 | mountPath: /var/run/docker.sock 70 | readOnly: true 71 | - name: usr-src-path # BPF (read-only) 72 | mountPath: /usr/src 73 | readOnly: true 74 | - name: lib-modules-path # BPF (read-only) 75 | mountPath: /lib/modules 76 | readOnly: true 77 | - name: sys-fs-bpf-path # BPF (read-write) 78 | mountPath: /sys/fs/bpf 79 | - name: sys-kernel-debug-path # BPF (read-write) 80 | mountPath: /sys/kernel/debug 81 | # - name: etc-apparmor-d-path # AppArmor (read-write) 82 | # mountPath: /etc/apparmor.d 83 | - name: os-release-path # OS (read-only) 84 | mountPath: /media/root/etc/os-release 85 | readOnly: true 86 | livenessProbe: 87 | exec: 88 | command: 89 | - /bin/bash 90 | - -c 91 | - | 92 | if [ -z $(pgrep kvmsoperator) ]; then 93 | exit 1; 94 | fi; 95 | initialDelaySeconds: 60 96 | periodSeconds: 10 97 | terminationMessagePolicy: File 98 | terminationMessagePath: /dev/termination-log 99 | terminationGracePeriodSeconds: 30 100 | volumes: 101 | - name: docker-sock-path # docker 102 | hostPath: 103 | path: /var/run/docker.sock 104 | type: Socket 105 | - name: usr-src-path # BPF 106 | hostPath: 107 | path: /usr/src 108 | type: Directory 109 | - name: lib-modules-path # BPF 110 | hostPath: 111 | path: /lib/modules 112 | type: Directory 113 | - name: sys-fs-bpf-path # BPF 114 | hostPath: 115 | path: /sys/fs/bpf 116 | type: Directory 117 | - name: sys-kernel-debug-path # BPF 118 | hostPath: 119 | path: /sys/kernel/debug 120 | type: Directory 121 | #- name: etc-apparmor-d-path # AppArmor 122 | # hostPath: 123 | # path: /etc/apparmor.d 124 | # type: DirectoryOrCreate 125 | - name: os-release-path # OS 126 | hostPath: 127 | path: /etc/os-release 128 | type: File 129 | -------------------------------------------------------------------------------- /src/operator/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Authors of KubeArmor 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package main 5 | 6 | import ( 7 | "flag" 8 | "os" 9 | "path/filepath" 10 | 11 | kg "github.com/kubearmor/KVMService/src/log" 12 | "github.com/kubearmor/KVMService/src/operator/core" 13 | ) 14 | 15 | func main() { 16 | if os.Geteuid() != 0 { 17 | kg.Printf("Need to have root privileges to run %s\n", os.Args[0]) 18 | return 19 | } 20 | 21 | dir, err := filepath.Abs(filepath.Dir(os.Args[0])) 22 | if err != nil { 23 | kg.Err(err.Error()) 24 | return 25 | } 26 | 27 | if err := os.Chdir(dir); err != nil { 28 | kg.Err(err.Error()) 29 | return 30 | } 31 | 32 | flag.Parse() 33 | 34 | core.KVMSOperatorDaemon() 35 | } 36 | -------------------------------------------------------------------------------- /src/service/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Authors of kvmservice 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | ifeq (,$(shell which govvv)) 5 | $(shell go install github.com/ahmetb/govvv@latest) 6 | endif 7 | 8 | CURDIR := $(shell pwd) 9 | CONTRIBDIR := $(realpath $(CURDIR)/../contribution) 10 | GO_EXEC := $(shell which go) 11 | LOGNAME := $(shell logname) 12 | NETNEXT := 1 13 | DLV_EXEC = $(GOPATH)/bin/dlv 14 | DLV_LPORT := 2345 15 | DLV_RPORT := $(shell expr $(DLV_LPORT) + $(NETNEXT)) 16 | KVMSERVICE_PID = $(shell pgrep kvmservice) 17 | GIT_INFO := $(shell govvv -flags) 18 | 19 | .PHONY: build 20 | build: 21 | cd $(CURDIR); go mod tidy 22 | cd $(CURDIR); go build -ldflags "-w -s ${GIT_INFO}" -o kvmservice main.go 23 | 24 | .PHONY: build-test 25 | build-test: 26 | cd $(CURDIR); go mod tidy 27 | cd $(CURDIR); sudo -E $(GO_EXEC) test -covermode=atomic -coverpkg=./... -c . -o kvmservice 28 | 29 | .PHONY: run 30 | run: build 31 | cd $(CURDIR); sudo rm -f /tmp/kvmservice.log 32 | cd $(CURDIR); sudo -E ./kvmservice -port=32769 -ipAddress="1.1.1.1" #-logPath=/tmp/kvmservice.log 33 | 34 | .PHONY: run-per-pod 35 | run-per-pod: build 36 | cd $(CURDIR); sudo rm -f /tmp/kvmservice.log 37 | cd $(CURDIR); sudo -E ./kvmservice #-logPath=/tmp/kvmservice.log -enableEnforcerPerPod 38 | 39 | .PHONY: run-with-host 40 | run-with-host: build 41 | cd $(CURDIR); sudo rm -f /tmp/kvmservice.log 42 | cd $(CURDIR); sudo -E ./kvmservice #-logPath=/tmp/kvmservice.log -enableHostPolicy -enableExternalWorkloadPolicy 43 | 44 | .PHONY: test 45 | test: 46 | cd $(CURDIR)/feeder; go mod tidy 47 | cd $(CURDIR)/feeder; go clean -testcache .; go test -v . 48 | 49 | .PHONY: testall 50 | testall: 51 | cd $(CURDIR)/feeder; go mod tidy 52 | cd $(CURDIR)/feeder; go clean -testcache .; go test -v -coverprofile=.coverprofile . 53 | cd $(CURDIR)/enforcer; go mod tidy 54 | cd $(CURDIR)/enforcer; go clean -testcache .; sudo -E $(GO_EXEC) test -v -coverprofile=.coverprofile . 55 | cd $(CURDIR)/monitor; go mod tidy 56 | cd $(CURDIR)/monitor; go clean -testcache .; sudo -E $(GO_EXEC) test -v -coverprofile=.coverprofile . 57 | 58 | .PHONY: gofmt 59 | gofmt: 60 | cd $(CURDIR); gofmt -s -d $(shell find . -type f -name '*.go' -print) 61 | 62 | .PHONY: golint 63 | golint: 64 | golangci-lint run 65 | #ifeq (, $(shell which golint)) 66 | # @{ \ 67 | # set -e ;\ 68 | # GOLINT_TMP_DIR=$$(mktemp -d) ;\ 69 | # cd $$GOLINT_TMP_DIR ;\ 70 | # go mod init tmp ;\ 71 | # go get -u golang.org/x/lint/golint ;\ 72 | # rm -rf $$GOLINT_TMP_DIR ;\ 73 | # } 74 | #endif 75 | # cd $(CURDIR); golint ./... 76 | 77 | .PHONY: gosec 78 | gosec: 79 | ifeq (, $(shell which gosec)) 80 | @{ \ 81 | set -e ;\ 82 | GOSEC_TMP_DIR=$$(mktemp -d) ;\ 83 | cd $$GOSEC_TMP_DIR ;\ 84 | go mod init tmp ;\ 85 | go get -u github.com/securego/gosec/v2/cmd/gosec ;\ 86 | rm -rf $$GOSEC_TMP_DIR ;\ 87 | } 88 | endif 89 | cd $(CURDIR); gosec ./... 90 | 91 | .PHONY: clean 92 | clean: 93 | cd $(CURDIR); sudo rm -f kvmservice /tmp/kvmservice.log 94 | cd $(CURDIR); find . -name .coverprofile | xargs -I {} rm {} 95 | $(CURDIR)/build/clean_source_files.sh 96 | 97 | .PHONY: vagrant-check 98 | vagrant-check: 99 | ifeq ($(LOGNAME), vagrant) 100 | $(error rule must be called from outside the vagrant environment) 101 | endif 102 | 103 | .PHONY: vagrant-up 104 | vagrant-up: vagrant-check 105 | cd $(CONTRIBDIR)/vagrant; NETNEXT=$(NETNEXT) DLV_RPORT=$(DLV_RPORT) vagrant up; true 106 | 107 | .PHONY: vagrant-status 108 | vagrant-status: vagrant-check 109 | cd $(CONTRIBDIR)/vagrant; NETNEXT=$(NETNEXT) DLV_RPORT=$(DLV_RPORT) vagrant status; true 110 | 111 | .PHONY: vagrant-reload 112 | vagrant-reload: vagrant-check 113 | cd $(CONTRIBDIR)/vagrant; NETNEXT=$(NETNEXT) DLV_RPORT=$(DLV_RPORT) vagrant reload; true 114 | 115 | .PHONY: vagrant-ssh 116 | vagrant-ssh: vagrant-check 117 | cd $(CONTRIBDIR)/vagrant; NETNEXT=$(NETNEXT) DLV_RPORT=$(DLV_RPORT) vagrant ssh; true 118 | 119 | .PHONY: vagrant-halt 120 | vagrant-halt: vagrant-check 121 | cd $(CONTRIBDIR)/vagrant; NETNEXT=$(NETNEXT) DLV_RPORT=$(DLV_RPORT) vagrant halt; true 122 | 123 | .PHONY: vagrant-destroy 124 | vagrant-destroy: vagrant-check 125 | cd $(CONTRIBDIR)/vagrant; NETNEXT=$(NETNEXT) DLV_RPORT=$(DLV_RPORT) vagrant destroy; true 126 | 127 | $(DLV_EXEC): 128 | go get -u github.com/go-delve/delve/cmd/dlv 129 | 130 | .PHONY: debug-attach 131 | debug-attach: $(DLV_EXEC) 132 | ifeq ($(KVMSERVICE_PID), ) 133 | $(error kvmservice must be running - execute 'make run' first) 134 | endif 135 | sudo $(DLV_EXEC) attach $(KVMSERVICE_PID) --headless -l=:$(DLV_LPORT) --log --api-version 2 $(CURDIR) 136 | -------------------------------------------------------------------------------- /src/service/build/Dockerfile.kvmservice: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | # Copyright 2021 Authors of KVMService 3 | 4 | ### Builder 5 | 6 | FROM golang:1.17.1-alpine3.14 as builder 7 | 8 | RUN apk update 9 | RUN apk add --no-cache bash git wget python3 linux-headers build-base clang clang-dev libc-dev bcc-dev 10 | 11 | WORKDIR /usr/src/KVMService 12 | 13 | COPY ./KVMService ./KVMService 14 | 15 | WORKDIR /usr/src/KVMService/KVMService/service 16 | 17 | RUN ./patch.sh 18 | RUN GOOS=linux GOARCH=amd64 go build -a -ldflags '-s -w' -o kvmservice main.go 19 | 20 | ### Make executable image 21 | 22 | FROM alpine:3.14 23 | 24 | RUN apk update 25 | RUN echo "@community http://dl-cdn.alpinelinux.org/alpine/edge/community" | tee -a /etc/apk/repositories 26 | RUN echo "@testing http://dl-cdn.alpinelinux.org/alpine/edge/testing" | tee -a /etc/apk/repositories 27 | 28 | RUN apk update 29 | RUN apk add bash curl procps bcc@community bcc-dev@community 30 | RUN apk add apparmor@community apparmor-utils@community kubectl@testing 31 | 32 | COPY --from=builder /usr/src/KVMService/KVMService/service/kvmservice /KVMService/kvmservice 33 | 34 | ENTRYPOINT ["/KVMService/kvmservice"] 35 | -------------------------------------------------------------------------------- /src/service/build/Makefile: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | # Copyright 2021 Authors of KubeArmor 3 | 4 | CURDIR=$(shell pwd) 5 | 6 | .PHONY: build 7 | build: 8 | $(CURDIR)/build_kvmservice.sh 9 | #$(CURDIR)/push_kubearmor.sh 10 | -------------------------------------------------------------------------------- /src/service/build/build_kvmservice.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # SPDX-License-Identifier: Apache-2.0 3 | # Copyright 2021 Authors of KVMService 4 | 5 | realpath() { 6 | CURR=$PWD 7 | 8 | cd "$(dirname "$0")" 9 | LINK=$(readlink "$(basename "$0")") 10 | 11 | while [ "$LINK" ]; do 12 | cd "$(dirname "$LINK")" 13 | LINK=$(readlink "$(basename "$1")") 14 | done 15 | 16 | REALPATH="$PWD/$(basename "$1")" 17 | echo "$REALPATH" 18 | 19 | cd $CURR 20 | } 21 | 22 | ARMOR_HOME=`dirname $(realpath "$0")`/.. 23 | cd $ARMOR_HOME/build 24 | 25 | VERSION=latest 26 | 27 | # check version 28 | if [ ! -z $1 ]; then 29 | VERSION=$1 30 | fi 31 | 32 | # remove old images 33 | docker images | grep kvmservice | awk '{print $3}' | xargs -I {} docker rmi -f {} 2> /dev/null 34 | 35 | echo "[INFO] Removed existing kubearmor/kvmservice images" 36 | 37 | # remove old files (just in case) 38 | $ARMOR_HOME/build/clean_source_files.sh 39 | 40 | echo "[INFO] Removed source files just in case" 41 | 42 | # copy files to build 43 | $ARMOR_HOME/build/copy_source_files.sh 44 | 45 | echo "[INFO] Copied new source files" 46 | 47 | # build a new image 48 | echo "[INFO] Building kubearmor/kvmservice:$VERSION" 49 | docker build -t kubearmor/kvmservice:$VERSION . -f $ARMOR_HOME/build/Dockerfile.kvmservice 50 | 51 | if [ $? != 0 ]; then 52 | echo "[FAILED] Failed to build kubearmor/kvmservice:$VERSION" 53 | exit 1 54 | else 55 | echo "[PASSED] Built kubearmor/kvmservice:$VERSION" 56 | fi 57 | 58 | # remove copied files 59 | $ARMOR_HOME/build/clean_source_files.sh 60 | 61 | echo "[INFO] Removed source files" 62 | exit 0 63 | -------------------------------------------------------------------------------- /src/service/build/clean_source_files.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # SPDX-License-Identifier: Apache-2.0 3 | # Copyright 2021 Authors of KubeArmor 4 | 5 | realpath() { 6 | CURR=$PWD 7 | 8 | cd "$(dirname "$0")" 9 | LINK=$(readlink "$(basename "$0")") 10 | 11 | while [ "$LINK" ]; do 12 | cd "$(dirname "$LINK")" 13 | LINK=$(readlink "$(basename "$1")") 14 | done 15 | 16 | REALPATH="$PWD/$(basename "$1")" 17 | echo "$REALPATH" 18 | 19 | cd $CURR 20 | } 21 | 22 | ARMOR_HOME=`dirname $(realpath "$0")`/.. 23 | 24 | rm -rf $ARMOR_HOME/build/KVMService 25 | -------------------------------------------------------------------------------- /src/service/build/copy_source_files.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # SPDX-License-Identifier: Apache-2.0 3 | # Copyright 2021 Authors of KVMService 4 | 5 | realpath() { 6 | CURR=$PWD 7 | 8 | cd "$(dirname "$0")" 9 | LINK=$(readlink "$(basename "$0")") 10 | 11 | while [ "$LINK" ]; do 12 | cd "$(dirname "$LINK")" 13 | LINK=$(readlink "$(basename "$1")") 14 | done 15 | 16 | REALPATH="$PWD/$(basename "$1")" 17 | echo "$REALPATH" 18 | 19 | cd $CURR 20 | } 21 | 22 | ARMOR_HOME=`dirname $(realpath "$0")`/.. 23 | SERVICE_PATH=`dirname $(realpath "$0")`/.. 24 | 25 | mkdir -p $ARMOR_HOME/build/KVMService 26 | mkdir -p $ARMOR_HOME/build/KVMService/service 27 | 28 | # copy files to build 29 | cp -r $SERVICE_PATH/../common/ $ARMOR_HOME/build/KVMService/ 30 | cp -r $SERVICE_PATH/../constants/ $ARMOR_HOME/build/KVMService/ 31 | cp -r $SERVICE_PATH/../etcd/ $ARMOR_HOME/build/KVMService/ 32 | cp -r $SERVICE_PATH/../log/ $ARMOR_HOME/build/KVMService/ 33 | cp -r $SERVICE_PATH/../types/ $ARMOR_HOME/build/KVMService/ 34 | cp -r $SERVICE_PATH/core/ $ARMOR_HOME/build/KVMService/service 35 | cp -r $SERVICE_PATH/genscript/ $ARMOR_HOME/build/KVMService/service 36 | cp -r $SERVICE_PATH/server/ $ARMOR_HOME/build/KVMService/service 37 | cp -r $SERVICE_PATH/protobuf/ $ARMOR_HOME/build/KVMService/service 38 | cp $SERVICE_PATH/go.mod $ARMOR_HOME/build/KVMService/service 39 | cp $SERVICE_PATH/go.sum $ARMOR_HOME/build/KVMService/service 40 | cp $SERVICE_PATH/main.go $ARMOR_HOME/build/KVMService/service 41 | 42 | cp $SERVICE_PATH/build/patch.sh $ARMOR_HOME/build/KVMService/service 43 | cp $SERVICE_PATH/build/patch_selinux.sh $ARMOR_HOME/build/KVMService/service 44 | -------------------------------------------------------------------------------- /src/service/build/patch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # SPDX-License-Identifier: Apache-2.0 3 | # Copyright 2021 Authors of KubeArmor 4 | 5 | # download gobpf 6 | go get -u github.com/iovisor/gobpf 7 | 8 | # fix module.go 9 | for GOBPF in $(ls $GOPATH/pkg/mod/github.com/iovisor); 10 | do 11 | echo $GOBPF 12 | sed -i 's/C.bpf_attach_uprobe(C.int(fd), attachType, evNameCS, binaryPathCS, (C.uint64_t)(addr), (C.pid_t)(pid), 0)/C.bpf_attach_uprobe(C.int(fd), attachType, evNameCS, binaryPathCS, (C.uint64_t)(addr), (C.pid_t)(pid))/g' $GOPATH/pkg/mod/github.com/iovisor/$GOBPF/bcc/module.go 13 | done 14 | -------------------------------------------------------------------------------- /src/service/build/patch_selinux.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # SPDX-License-Identifier: Apache-2.0 3 | # Copyright 2021 Authors of KubeArmor 4 | 5 | # download gobpf 6 | go get -u github.com/iovisor/gobpf 7 | 8 | # fix module.go 9 | for GOBPF in $(ls $GOPATH/pkg/mod/github.com/iovisor); 10 | do 11 | echo $GOBPF 12 | sed -i 's/C.bpf_attach_uprobe(C.int(fd), attachType, evNameCS, binaryPathCS, (C.uint64_t)(addr), (C.pid_t)(pid), 0)/C.bpf_attach_uprobe(C.int(fd), attachType, evNameCS, binaryPathCS, (C.uint64_t)(addr), (C.pid_t)(pid))/g' $GOPATH/pkg/mod/github.com/iovisor/$GOBPF/bcc/module.go 13 | sed -i "s/C.bpf_module_create_c_from_string(cs, 2, (\*\*C.char)(\&cflagsC\[0\]), C.int(len(cflagsC)), (C.bool)(true), nil)/C.bpf_module_create_c_from_string(cs, 2, (\*\*C.char)(\&cflagsC\[0\]), C.int(len(cflagsC)), (C.bool)(true))/g" $GOPATH/pkg/mod/github.com/iovisor/$GOBPF/bcc/module.go 14 | sed -i 's/C.bcc_func_load(bpf.p, C.int(uint32(progType)), nameCS, start, size, license, version, C.int(logLevel), logBufP, C.uint(len(logBuf)), nil)/C.bcc_func_load(bpf.p, C.int(uint32(progType)), nameCS, start, size, license, version, C.int(logLevel), logBufP, C.uint(len(logBuf)))/g' $GOPATH/pkg/mod/github.com/iovisor/$GOBPF/bcc/module.go 15 | done 16 | -------------------------------------------------------------------------------- /src/service/core/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/kubearmor/KVMService/src/service/core 2 | 3 | go 1.17 4 | 5 | replace ( 6 | github.com/kubearmor/KVMService/src/common => ../../common 7 | github.com/kubearmor/KVMService/src/constants => ../../constants 8 | github.com/kubearmor/KVMService/src/etcd => ../../etcd 9 | github.com/kubearmor/KVMService/src/log => ../../log 10 | github.com/kubearmor/KVMService/src/service/genscript => ../genscript 11 | github.com/kubearmor/KVMService/src/service/protobuf => ../protobuf 12 | github.com/kubearmor/KVMService/src/service/server => ../server 13 | github.com/kubearmor/KVMService/src/types => ../../types 14 | ) 15 | 16 | require ( 17 | github.com/kubearmor/KVMService/src/common v0.0.0-00010101000000-000000000000 18 | github.com/kubearmor/KVMService/src/constants v0.0.0-00010101000000-000000000000 19 | github.com/kubearmor/KVMService/src/etcd v0.0.0-00010101000000-000000000000 20 | github.com/kubearmor/KVMService/src/log v0.0.0-00010101000000-000000000000 21 | github.com/kubearmor/KVMService/src/service/server v0.0.0-00010101000000-000000000000 22 | github.com/kubearmor/KVMService/src/types v0.0.0-00010101000000-000000000000 23 | k8s.io/apimachinery v0.22.4 24 | k8s.io/client-go v0.22.4 25 | ) 26 | 27 | require ( 28 | github.com/coreos/go-semver v0.3.0 // indirect 29 | github.com/coreos/go-systemd/v22 v22.3.2 // indirect 30 | github.com/davecgh/go-spew v1.1.1 // indirect 31 | github.com/go-logr/logr v0.4.0 // indirect 32 | github.com/gogo/protobuf v1.3.2 // indirect 33 | github.com/golang/protobuf v1.5.2 // indirect 34 | github.com/google/go-cmp v0.5.5 // indirect 35 | github.com/google/gofuzz v1.1.0 // indirect 36 | github.com/googleapis/gnostic v0.5.5 // indirect 37 | github.com/imdario/mergo v0.3.5 // indirect 38 | github.com/json-iterator/go v1.1.11 // indirect 39 | github.com/kubearmor/KVMService/src/service/genscript v0.0.0-00010101000000-000000000000 // indirect 40 | github.com/kubearmor/KVMService/src/service/protobuf v0.0.0-00010101000000-000000000000 // indirect 41 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 42 | github.com/modern-go/reflect2 v1.0.1 // indirect 43 | github.com/spf13/pflag v1.0.5 // indirect 44 | go.etcd.io/etcd/api/v3 v3.5.1 // indirect 45 | go.etcd.io/etcd/client/pkg/v3 v3.5.1 // indirect 46 | go.etcd.io/etcd/client/v3 v3.5.1 // indirect 47 | go.uber.org/atomic v1.7.0 // indirect 48 | go.uber.org/multierr v1.6.0 // indirect 49 | go.uber.org/zap v1.19.1 // indirect 50 | golang.org/x/net v0.0.0-20210520170846-37e1c6afe023 // indirect 51 | golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect 52 | golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 // indirect 53 | golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d // indirect 54 | golang.org/x/text v0.3.6 // indirect 55 | golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect 56 | google.golang.org/appengine v1.6.5 // indirect 57 | google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c // indirect 58 | google.golang.org/grpc v1.42.0 // indirect 59 | google.golang.org/protobuf v1.27.1 // indirect 60 | gopkg.in/inf.v0 v0.9.1 // indirect 61 | gopkg.in/yaml.v2 v2.4.0 // indirect 62 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect 63 | k8s.io/api v0.22.4 // indirect 64 | k8s.io/klog/v2 v2.9.0 // indirect 65 | k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a // indirect 66 | sigs.k8s.io/structured-merge-diff/v4 v4.1.2 // indirect 67 | sigs.k8s.io/yaml v1.2.0 // indirect 68 | ) 69 | -------------------------------------------------------------------------------- /src/service/core/kvmService.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2021 Authors of KubeArmor 3 | 4 | package core 5 | 6 | import ( 7 | //"context" 8 | 9 | "log" 10 | "net" 11 | "os" 12 | "os/signal" 13 | "strconv" 14 | "sync" 15 | "syscall" 16 | "time" 17 | 18 | kc "github.com/kubearmor/KVMService/src/common" 19 | ct "github.com/kubearmor/KVMService/src/constants" 20 | etcd "github.com/kubearmor/KVMService/src/etcd" 21 | kg "github.com/kubearmor/KVMService/src/log" 22 | gs "github.com/kubearmor/KVMService/src/service/genscript" 23 | ks "github.com/kubearmor/KVMService/src/service/server" 24 | tp "github.com/kubearmor/KVMService/src/types" 25 | ) 26 | 27 | // ClientConn is the wrapper for a grpc client conn 28 | type ClientConn struct { 29 | // conn *grpc.ClientConn 30 | // unhealthy bool 31 | } 32 | 33 | // ====================== // 34 | // == KubeArmor Daemon == // 35 | // ====================== // 36 | 37 | // StopChan Channel 38 | var StopChan chan struct{} 39 | 40 | // init Function 41 | func init() { 42 | StopChan = make(chan struct{}) 43 | } 44 | 45 | // KVMS Structure 46 | type KVMS struct { 47 | EtcdClient *etcd.EtcdClient 48 | Server *ks.Server 49 | 50 | // gRPC 51 | gRPCPort string 52 | LogPath string 53 | LogFilter string 54 | 55 | IdentityConnPool []ClientConn 56 | 57 | MapEtcdEWIdentityLabels map[string]string 58 | EtcdEWLabels []string 59 | 60 | // Host Security policies 61 | HostSecurityPolicies []tp.HostSecurityPolicy 62 | HostSecurityPoliciesLock *sync.RWMutex 63 | 64 | // External workload policies and mappers 65 | ExternalWorkloadSecurityPolicies []tp.ExternalWorkloadSecurityPolicy 66 | ExternalWorkloadSecurityPoliciesLock *sync.RWMutex 67 | 68 | MapIdentityToLabel map[uint16]string 69 | MapLabelToIdentities map[string][]uint16 70 | MapExternalWorkloadConnIdentity map[uint16]ClientConn 71 | 72 | ClusterPort uint16 73 | ClusteripAddress string 74 | PodIpAddress string 75 | 76 | // WgDaemon Handler 77 | WgDaemon sync.WaitGroup 78 | } 79 | 80 | // NewKVMSDaemon Function 81 | func NewKVMSDaemon(port int, ipAddress string) *KVMS { 82 | kg.Print("Initializing all the KVMS daemon attributes") 83 | dm := new(KVMS) 84 | 85 | dm.EtcdClient = etcd.NewEtcdClient() 86 | 87 | dm.MapEtcdEWIdentityLabels = make(map[string]string) 88 | dm.EtcdEWLabels = make([]string, 0) 89 | 90 | dm.gRPCPort = "" 91 | dm.LogPath = "" 92 | dm.LogFilter = "" 93 | dm.IdentityConnPool = nil 94 | 95 | dm.ClusterPort = uint16(port) 96 | dm.ClusteripAddress = ipAddress 97 | conn, err := net.Dial("udp", "8.8.8.8:80") 98 | if err != nil { 99 | log.Fatal(err) 100 | } 101 | defer conn.Close() 102 | 103 | localAddr := conn.LocalAddr().(*net.UDPAddr) 104 | dm.PodIpAddress = localAddr.IP.String() 105 | dm.Server = ks.NewServerInit(dm.PodIpAddress, dm.ClusteripAddress, strconv.FormatUint(uint64(dm.ClusterPort), 10), dm.EtcdClient) 106 | 107 | dm.HostSecurityPolicies = []tp.HostSecurityPolicy{} 108 | dm.HostSecurityPoliciesLock = new(sync.RWMutex) 109 | dm.ExternalWorkloadSecurityPoliciesLock = new(sync.RWMutex) 110 | 111 | dm.MapIdentityToLabel = make(map[uint16]string) 112 | dm.MapLabelToIdentities = make(map[string][]uint16) 113 | dm.MapExternalWorkloadConnIdentity = make(map[uint16]ClientConn) 114 | 115 | dm.WgDaemon = sync.WaitGroup{} 116 | kg.Print("KVMService attributes got initialized\n") 117 | 118 | return dm 119 | } 120 | 121 | // DestroyKVMS Function 122 | func (dm *KVMS) DestroyKVMS() { 123 | 124 | // wait for a while 125 | time.Sleep(time.Second * 1) 126 | 127 | // wait for other routines 128 | kg.Print("Waiting for remaining routine terminations") 129 | dm.WgDaemon.Wait() 130 | } 131 | 132 | // ==================== // 133 | // == Signal Handler == // 134 | // ==================== // 135 | 136 | // GetOSSigChannel Function 137 | func GetOSSigChannel() chan os.Signal { 138 | c := make(chan os.Signal, 1) 139 | 140 | signal.Notify(c, 141 | syscall.SIGHUP, 142 | syscall.SIGINT, 143 | syscall.SIGTERM, 144 | syscall.SIGQUIT, 145 | os.Interrupt) 146 | 147 | return c 148 | } 149 | 150 | // ========== // 151 | // == Main == // 152 | // ========== // 153 | 154 | // KVMSDaemon Function 155 | func KVMSDaemon(portPtr int) { 156 | 157 | // Get kvmservice external ip 158 | externalIp, err := kc.GetExternalIP(ct.KvmServiceAccountName) 159 | if err != nil { 160 | kg.Err(err.Error()) 161 | return 162 | } 163 | 164 | // create a daemon 165 | dm := NewKVMSDaemon(portPtr, externalIp) 166 | 167 | // wait for a while 168 | time.Sleep(time.Second * 1) 169 | 170 | // == // 171 | gs.InitGenScript(dm.ClusterPort, dm.ClusteripAddress) 172 | 173 | if K8s.InitK8sClient() { 174 | // watch host security policies 175 | kg.Print("K8S Client is successfully initialize") 176 | 177 | kg.Print("Watcher triggered for the host policies") 178 | go dm.WatchHostSecurityPolicies() 179 | 180 | kg.Print("Triggered the keepalive ETCD client") 181 | go dm.EtcdClient.KeepAliveEtcdConnection() 182 | 183 | kg.Print("Starting gRPC server") 184 | go dm.Server.InitServer() 185 | } else { 186 | kg.Print("K8S client initialization got failed") 187 | } 188 | 189 | // wait for a while 190 | time.Sleep(time.Second * 1) 191 | 192 | // listen for interrupt signals 193 | sigChan := GetOSSigChannel() 194 | <-sigChan 195 | close(StopChan) 196 | close(ks.PolicyChan) 197 | 198 | // destroy the daemon 199 | dm.DestroyKVMS() 200 | } 201 | -------------------------------------------------------------------------------- /src/service/core/kvmsUpdate.go: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2021 Authors of KubeArmor 3 | 4 | package core 5 | 6 | import ( 7 | "encoding/json" 8 | "io" 9 | "log" 10 | 11 | //"sort" 12 | "strings" 13 | 14 | //"math/rand" 15 | "context" 16 | "time" 17 | 18 | kl "github.com/kubearmor/KVMService/src/common" 19 | ct "github.com/kubearmor/KVMService/src/constants" 20 | kg "github.com/kubearmor/KVMService/src/log" 21 | ks "github.com/kubearmor/KVMService/src/service/server" 22 | tp "github.com/kubearmor/KVMService/src/types" 23 | ) 24 | 25 | func Find(slice []uint16, val uint16) (int, bool) { 26 | for i, item := range slice { 27 | if item == val { 28 | return i, true 29 | } 30 | } 31 | return -1, false 32 | } 33 | 34 | /* TODO : Code currently not in use 35 | func (dm *KVMS) mGetAllEtcdEWLabels() { 36 | kg.Print("Getting the External workload labels from ETCD") 37 | 38 | etcdLabels, err := dm.EtcdClient.EtcdGet(context.TODO(), ct.KvmOprLabelToIdentities) 39 | if err != nil { 40 | log.Fatal(err) 41 | return 42 | } 43 | 44 | for key, value := range etcdLabels { 45 | s := strings.Split(key, "/") 46 | identity := s[len(s)-1] 47 | dm.MapEtcdEWIdentityLabels[identity] = value 48 | dm.EtcdEWLabels = append(dm.EtcdEWLabels, value) 49 | 50 | idNum, _ := strconv.ParseUint(identity, 0, 16) 51 | _, found := Find(dm.MapLabelToIdentities[value], uint16(idNum)) 52 | if !found { 53 | dm.MapLabelToIdentities[value] = append(dm.MapLabelToIdentities[value], uint16(idNum)) 54 | } 55 | } 56 | } 57 | */ 58 | 59 | func (dm *KVMS) GetAllEtcdEWLabels() { 60 | kg.Print("Getting the External workload labels from ETCD") 61 | etcdLabels, err := dm.EtcdClient.EtcdGet(context.TODO(), ct.KvmOprLabelToIdentities) 62 | if err != nil { 63 | log.Fatal(err) 64 | return 65 | } 66 | 67 | for key := range etcdLabels { 68 | s := strings.Split(key, "/") 69 | label := s[len(s)-1] 70 | dm.EtcdEWLabels = append(dm.EtcdEWLabels, label) 71 | } 72 | 73 | for _, label := range dm.EtcdEWLabels { 74 | data, err := dm.EtcdClient.EtcdGetRaw(context.TODO(), ct.KvmOprLabelToIdentities+label) 75 | if err != nil { 76 | log.Fatal(err) 77 | return 78 | } 79 | 80 | for _, ev := range data.Kvs { 81 | var arr []uint16 82 | err := json.Unmarshal(ev.Value, &arr) 83 | if err != nil { 84 | log.Fatal(err) 85 | return 86 | } 87 | s := strings.Split(string(ev.Key), "/") 88 | dm.MapLabelToIdentities[s[len(s)-1]] = arr 89 | } 90 | } 91 | } 92 | 93 | func (dm *KVMS) PassOverToKVMSAgent(event tp.K8sKubeArmorHostPolicyEvent, identities []uint16) { 94 | eventWithIdentity := tp.K8sKubeArmorHostPolicyEventWithIdentity{} 95 | 96 | eventWithIdentity.Event = event 97 | eventWithIdentity.CloseConnection = false 98 | for _, identity := range identities { 99 | eventWithIdentity.Identity = identity 100 | kg.Printf("Sending the event towards the KVMAgent of identity:%v\n", identity) 101 | ks.PolicyChan <- eventWithIdentity 102 | } 103 | } 104 | 105 | func (dm *KVMS) GetIdentityFromLabelPool(label string) []uint16 { 106 | kg.Printf("Getting the identity from the pool => label:%s\n", label) 107 | return dm.MapLabelToIdentities[label] 108 | } 109 | 110 | // ================================= // 111 | // == Host Security Policy Update == // 112 | // ================================= // 113 | // UpdateHostSecurityPolicies Function 114 | func (dm *KVMS) UpdateHostSecurityPolicies(event tp.K8sKubeArmorHostPolicyEvent) { 115 | var identities []uint16 116 | var labels []string 117 | secPolicy := tp.HostSecurityPolicy{} 118 | 119 | secPolicy.Metadata = map[string]string{} 120 | secPolicy.Metadata["policyName"] = event.Object.Metadata.Name 121 | 122 | if err := kl.Clone(event.Object.Spec, &secPolicy.Spec); err != nil { 123 | log.Fatal("Failed to clone a spec") 124 | } 125 | 126 | for k, v := range secPolicy.Spec.NodeSelector.MatchLabels { 127 | labels = append(labels, k+"="+v) 128 | } 129 | 130 | dm.GetAllEtcdEWLabels() 131 | if dm.EtcdEWLabels == nil { 132 | kg.Err("No etcd keys") 133 | return 134 | } 135 | 136 | if kl.MatchIdentities(labels, dm.EtcdEWLabels) { 137 | for _, label := range labels { 138 | identities = dm.GetIdentityFromLabelPool(label) 139 | kg.Printf("External workload CRD matched with policy identity:%+v label:%s\n", identities, label) 140 | if len(identities) > 0 { 141 | dm.PassOverToKVMSAgent(event, identities) 142 | } 143 | } 144 | } 145 | } 146 | 147 | // WatchHostSecurityPolicies Function 148 | func (dm *KVMS) WatchHostSecurityPolicies() { 149 | for { 150 | if !K8s.CheckCustomResourceDefinition(ct.KhpCRDName) { 151 | time.Sleep(time.Second * 1) 152 | continue 153 | } 154 | 155 | if resp := K8s.WatchK8sHostSecurityPolicies(); resp != nil { 156 | defer resp.Body.Close() 157 | 158 | decoder := json.NewDecoder(resp.Body) 159 | for { 160 | event := tp.K8sKubeArmorHostPolicyEvent{} 161 | if err := decoder.Decode(&event); err == io.EOF { 162 | break 163 | } else if err != nil { 164 | break 165 | } 166 | 167 | if event.Object.Status.Status != "" && event.Object.Status.Status != "OK" { 168 | continue 169 | } 170 | 171 | kg.Print("Host policy got detected") 172 | dm.UpdateHostSecurityPolicies(event) 173 | } 174 | } 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /src/service/genscript/genscript.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Authors of KubeArmor 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package genscript 5 | 6 | import ( 7 | "strconv" 8 | 9 | kg "github.com/kubearmor/KVMService/src/log" 10 | ) 11 | 12 | var ( 13 | p GenScriptParams 14 | ScriptData string 15 | ) 16 | 17 | type GenScriptParams struct { 18 | port uint16 19 | ipAddress string 20 | } 21 | 22 | func InitGenScript(Port uint16, IpAddress string) { 23 | p.port = Port 24 | p.ipAddress = IpAddress 25 | } 26 | 27 | func addContent(content string) { 28 | ScriptData = ScriptData + content + "\n" 29 | } 30 | 31 | func GenerateEWInstallationScript(externalWorkload, identity string) string { 32 | 33 | ScriptData = "" 34 | 35 | kg.Printf("Generating the installation script =>") 36 | kg.Printf("ClusterIP:%s ClusterPort:%d ewName:%s identity:%s", p.ipAddress, p.port, externalWorkload, identity) 37 | 38 | addContent("#!/bin/bash") 39 | addContent("set -e") 40 | addContent("set -x") 41 | addContent("shopt -s extglob") 42 | addContent("") 43 | 44 | contentStr := "CLUSTER_PORT=" + strconv.FormatUint(uint64(p.port), 10) 45 | addContent(contentStr) 46 | contentStr = "CLUSTER_IP=" + p.ipAddress 47 | addContent(contentStr) 48 | addContent("") 49 | 50 | addContent("if [[ $(which docker) && $(docker --version) ]]; then") 51 | addContent(" echo \"Docker is installed!!!\"") 52 | addContent("else") 53 | addContent(" echo \"Failed: Docker is not installed!!!\"") 54 | addContent(" exit -1") 55 | addContent("fi") 56 | addContent("") 57 | 58 | contentStr = "WORKLOAD_IDENTITY=" + identity 59 | addContent(contentStr) 60 | addContent("") 61 | 62 | addContent("DOCKER_OPTS=\" -d -p 32767:32767 --log-driver syslog --restart always\"") 63 | addContent("DOCKER_OPTS+=\" --privileged --add-host kvms.kubearmor.io:$CLUSTER_IP\"") 64 | addContent("DOCKER_OPTS+=\" --env CLUSTER_PORT=$CLUSTER_PORT --env CLUSTER_IP=$CLUSTER_IP\"") 65 | addContent("DOCKER_OPTS+=\" --env WORKLOAD_IDENTITY=$WORKLOAD_IDENTITY\"") 66 | addContent("DOCKER_OPTS+=\" --volume /var/run/docker.sock:/var/run/docker.sock\"") 67 | addContent("DOCKER_OPTS+=\" --volume /usr/src:/usr/src\"") 68 | addContent("DOCKER_OPTS+=\" --volume /lib/modules:/lib/modules\"") 69 | addContent("DOCKER_OPTS+=\" --volume /sys/fs/bpf:/sys/fs/bpf\"") 70 | addContent("DOCKER_OPTS+=\" --volume /sys/kernel/debug:/sys/kernel/debug\"") 71 | addContent("DOCKER_OPTS+=\" --volume /etc/apparmor.d:/etc/apparmor.d\"") 72 | addContent("DOCKER_OPTS+=\" --volume /etc/os-release:/media/root/etc/os-release\"") 73 | addContent("") 74 | addContent("KUBEARMOR_OPTS=\" -enableKubeArmorvm=true -logPath=/tmp/kubearmor.log\"") 75 | addContent("") 76 | addContent("if [ -n \"$(sudo docker ps -a -q -f name=kubearmor)\" ]; then") 77 | addContent(" echo \"Shutting down running kubearmor agent\"") 78 | addContent(" sudo docker rm -f kubearmor || true") 79 | addContent("fi") 80 | addContent("") 81 | addContent("KUBEARMOR_IMAGE=\"kubearmor/kubearmor:latest\"") 82 | addContent("") 83 | addContent("echo \"Launching kubearmor agent...\"") 84 | addContent("sudo docker run --name kubearmor $DOCKER_OPTS $KUBEARMOR_IMAGE kubearmor $KUBEARMOR_OPTS") 85 | addContent("") 86 | 87 | kg.Printf("Script data is successfully generated!") 88 | 89 | return ScriptData 90 | } 91 | -------------------------------------------------------------------------------- /src/service/genscript/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/kubearmor/KVMService/src/service/genscript 2 | 3 | go 1.17 4 | 5 | replace github.com/kubearmor/KVMService/src/log => ../../log 6 | 7 | require github.com/kubearmor/KVMService/src/log v0.0.0-00010101000000-000000000000 8 | 9 | require ( 10 | go.uber.org/atomic v1.7.0 // indirect 11 | go.uber.org/multierr v1.6.0 // indirect 12 | go.uber.org/zap v1.19.1 // indirect 13 | ) 14 | -------------------------------------------------------------------------------- /src/service/genscript/go.sum: -------------------------------------------------------------------------------- 1 | github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= 2 | github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= 3 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 4 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 5 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 6 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 7 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 8 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 9 | github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= 10 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 11 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 12 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 13 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 14 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 15 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= 16 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 17 | github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= 18 | go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= 19 | go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= 20 | go.uber.org/goleak v1.1.11-0.20210813005559-691160354723 h1:sHOAIxRGBp443oHZIPB+HsUGaksVCXVQENPxwTfQdH4= 21 | go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= 22 | go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= 23 | go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= 24 | go.uber.org/zap v1.19.1 h1:ue41HOKd1vGURxrmeKIgELGb3jPW9DMUDGtsinblHwI= 25 | go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= 26 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 27 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 28 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 29 | golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 30 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 31 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 32 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 33 | golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= 34 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 35 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 36 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 37 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 38 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 39 | golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 40 | golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 41 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 42 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 43 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 44 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 45 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 46 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 47 | golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 48 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 49 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 50 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 51 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 52 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 53 | gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= 54 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 55 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 56 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= 57 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 58 | -------------------------------------------------------------------------------- /src/service/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/kubearmor/KVMService/src/service 2 | 3 | go 1.17 4 | 5 | replace ( 6 | github.com/kubearmor/KVMService/src/common => ../common 7 | github.com/kubearmor/KVMService/src/constants => ../constants 8 | github.com/kubearmor/KVMService/src/etcd => ../etcd 9 | github.com/kubearmor/KVMService/src/log => ../log 10 | github.com/kubearmor/KVMService/src/service/core => ./core 11 | github.com/kubearmor/KVMService/src/service/genscript => ./genscript 12 | github.com/kubearmor/KVMService/src/service/protobuf => ./protobuf 13 | github.com/kubearmor/KVMService/src/service/server => ./server 14 | github.com/kubearmor/KVMService/src/types => ../types 15 | ) 16 | 17 | require ( 18 | github.com/kubearmor/KVMService/src/log v0.0.0-00010101000000-000000000000 19 | github.com/kubearmor/KVMService/src/service/core v0.0.0-00010101000000-000000000000 20 | ) 21 | 22 | require ( 23 | github.com/coreos/go-semver v0.3.0 // indirect 24 | github.com/coreos/go-systemd/v22 v22.3.2 // indirect 25 | github.com/davecgh/go-spew v1.1.1 // indirect 26 | github.com/go-logr/logr v0.4.0 // indirect 27 | github.com/gogo/protobuf v1.3.2 // indirect 28 | github.com/golang/protobuf v1.5.2 // indirect 29 | github.com/google/go-cmp v0.5.5 // indirect 30 | github.com/google/gofuzz v1.1.0 // indirect 31 | github.com/googleapis/gnostic v0.5.5 // indirect 32 | github.com/imdario/mergo v0.3.5 // indirect 33 | github.com/json-iterator/go v1.1.11 // indirect 34 | github.com/kubearmor/KVMService/src/common v0.0.0-00010101000000-000000000000 // indirect 35 | github.com/kubearmor/KVMService/src/constants v0.0.0-00010101000000-000000000000 // indirect 36 | github.com/kubearmor/KVMService/src/etcd v0.0.0-00010101000000-000000000000 // indirect 37 | github.com/kubearmor/KVMService/src/service/genscript v0.0.0-00010101000000-000000000000 // indirect 38 | github.com/kubearmor/KVMService/src/service/protobuf v0.0.0-00010101000000-000000000000 // indirect 39 | github.com/kubearmor/KVMService/src/service/server v0.0.0-00010101000000-000000000000 // indirect 40 | github.com/kubearmor/KVMService/src/types v0.0.0-00010101000000-000000000000 // indirect 41 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 42 | github.com/modern-go/reflect2 v1.0.1 // indirect 43 | github.com/spf13/pflag v1.0.5 // indirect 44 | go.etcd.io/etcd/api/v3 v3.5.1 // indirect 45 | go.etcd.io/etcd/client/pkg/v3 v3.5.1 // indirect 46 | go.etcd.io/etcd/client/v3 v3.5.1 // indirect 47 | go.uber.org/atomic v1.7.0 // indirect 48 | go.uber.org/multierr v1.6.0 // indirect 49 | go.uber.org/zap v1.19.1 // indirect 50 | golang.org/x/net v0.0.0-20210520170846-37e1c6afe023 // indirect 51 | golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect 52 | golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 // indirect 53 | golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d // indirect 54 | golang.org/x/text v0.3.6 // indirect 55 | golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect 56 | google.golang.org/appengine v1.6.5 // indirect 57 | google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c // indirect 58 | google.golang.org/grpc v1.42.0 // indirect 59 | google.golang.org/protobuf v1.27.1 // indirect 60 | gopkg.in/inf.v0 v0.9.1 // indirect 61 | gopkg.in/yaml.v2 v2.4.0 // indirect 62 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect 63 | k8s.io/api v0.22.4 // indirect 64 | k8s.io/apimachinery v0.22.4 // indirect 65 | k8s.io/client-go v0.22.4 // indirect 66 | k8s.io/klog/v2 v2.9.0 // indirect 67 | k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a // indirect 68 | sigs.k8s.io/structured-merge-diff/v4 v4.1.2 // indirect 69 | sigs.k8s.io/yaml v1.2.0 // indirect 70 | ) 71 | -------------------------------------------------------------------------------- /src/service/kvmservice.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: kvmservice 5 | namespace: kube-system 6 | --- 7 | apiVersion: rbac.authorization.k8s.io/v1 8 | kind: ClusterRoleBinding 9 | metadata: 10 | name: kvmservice 11 | roleRef: 12 | apiGroup: rbac.authorization.k8s.io 13 | kind: ClusterRole 14 | name: cluster-admin 15 | subjects: 16 | - kind: ServiceAccount 17 | name: kvmservice 18 | namespace: kube-system 19 | --- 20 | apiVersion: v1 21 | kind: Service 22 | metadata: 23 | name: kvmservice 24 | namespace: kube-system 25 | spec: 26 | selector: 27 | kvmservice-app: kvmservice 28 | type: LoadBalancer 29 | ports: 30 | - port: 32770 31 | protocol: TCP 32 | targetPort: 32770 33 | --- 34 | apiVersion: apps/v1 35 | #kind: DaemonSet 36 | kind: Deployment 37 | metadata: 38 | name: kvmservice 39 | namespace: kube-system 40 | labels: 41 | kvmservice-app: kvmservice 42 | spec: 43 | replicas: 1 44 | selector: 45 | matchLabels: 46 | kvmservice-app: kvmservice 47 | template: 48 | metadata: 49 | labels: 50 | kvmservice-app: kvmservice 51 | annotations: 52 | container.apparmor.security.beta.kubernetes.io/kvmservice: unconfined 53 | spec: 54 | serviceAccountName: kvmservice 55 | nodeSelector: 56 | kubernetes.io/os: linux 57 | tolerations: 58 | - operator: Exists 59 | hostPID: true 60 | hostNetwork: true 61 | restartPolicy: Always 62 | dnsPolicy: ClusterFirstWithHostNet 63 | containers: 64 | - name: kvmservice 65 | image: seswarrajan/kvms:v0.5 66 | imagePullPolicy: Always 67 | securityContext: 68 | privileged: true 69 | args: ["-port=32770"] 70 | env: 71 | - name: ETCD_NAMESPACE 72 | value: "kube-system" 73 | - name: KVMSERVICE_NAMESPACE 74 | value: "kube-system" 75 | ports: 76 | - containerPort: 40400 77 | hostPort: 0 78 | volumeMounts: 79 | - name: docker-sock-path # docker (read-only) 80 | mountPath: /var/run/docker.sock 81 | readOnly: true 82 | - name: usr-src-path # BPF (read-only) 83 | mountPath: /usr/src 84 | readOnly: true 85 | - name: lib-modules-path # BPF (read-only) 86 | mountPath: /lib/modules 87 | readOnly: true 88 | - name: sys-fs-bpf-path # BPF (read-write) 89 | mountPath: /sys/fs/bpf 90 | - name: sys-kernel-debug-path # BPF (read-write) 91 | mountPath: /sys/kernel/debug 92 | # - name: etc-apparmor-d-path # AppArmor (read-write) 93 | # mountPath: /etc/apparmor.d 94 | - name: os-release-path # OS (read-only) 95 | mountPath: /media/root/etc/os-release 96 | readOnly: true 97 | livenessProbe: 98 | exec: 99 | command: 100 | - /bin/bash 101 | - -c 102 | - | 103 | if [ -z $(pgrep kvmservice) ]; then 104 | exit 1; 105 | fi; 106 | initialDelaySeconds: 60 107 | periodSeconds: 10 108 | terminationMessagePolicy: File 109 | terminationMessagePath: /dev/termination-log 110 | terminationGracePeriodSeconds: 30 111 | volumes: 112 | - name: docker-sock-path # docker 113 | hostPath: 114 | path: /var/run/docker.sock 115 | type: Socket 116 | - name: usr-src-path # BPF 117 | hostPath: 118 | path: /usr/src 119 | type: Directory 120 | - name: lib-modules-path # BPF 121 | hostPath: 122 | path: /lib/modules 123 | type: Directory 124 | - name: sys-fs-bpf-path # BPF 125 | hostPath: 126 | path: /sys/fs/bpf 127 | type: Directory 128 | - name: sys-kernel-debug-path # BPF 129 | hostPath: 130 | path: /sys/kernel/debug 131 | type: Directory 132 | #- name: etc-apparmor-d-path # AppArmor 133 | # hostPath: 134 | # path: /etc/apparmor.d 135 | # type: DirectoryOrCreate 136 | - name: os-release-path # OS 137 | hostPath: 138 | path: /etc/os-release 139 | type: File 140 | -------------------------------------------------------------------------------- /src/service/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Authors of KubeArmor 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package main 5 | 6 | import ( 7 | "flag" 8 | "os" 9 | "path/filepath" 10 | 11 | kg "github.com/kubearmor/KVMService/src/log" 12 | "github.com/kubearmor/KVMService/src/service/core" 13 | ) 14 | 15 | // GitCommit string passed from govvv 16 | var GitCommit string 17 | 18 | // GitBranch string passed from govvv 19 | var GitBranch string 20 | 21 | // BuildDate string passed from govvv 22 | var BuildDate string 23 | 24 | // Version string passed from govvv 25 | var Version string 26 | 27 | func printBuildDetails() { 28 | kg.Printf("BUILD-INFO: commit:%s, branch: %s, date: %s, version: %s", 29 | GitCommit, GitBranch, BuildDate, Version) 30 | } 31 | 32 | func main() { 33 | printBuildDetails() 34 | if os.Geteuid() != 0 { 35 | kg.Printf("Need to have root privileges to run %s\n", os.Args[0]) 36 | return 37 | } 38 | 39 | dir, err := filepath.Abs(filepath.Dir(os.Args[0])) 40 | if err != nil { 41 | kg.Err(err.Error()) 42 | return 43 | } 44 | 45 | if err := os.Chdir(dir); err != nil { 46 | kg.Err(err.Error()) 47 | return 48 | } 49 | 50 | portPtr := flag.Int("port", 40400, "Cluster Port") 51 | 52 | flag.Parse() 53 | 54 | // == // 55 | 56 | core.KVMSDaemon(*portPtr) 57 | 58 | // == // 59 | } 60 | -------------------------------------------------------------------------------- /src/service/patch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2021 Authors of KubeArmor 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | # download gobpf 6 | go get github.com/iovisor/gobpf 7 | 8 | # check sudo 9 | SUDO=OFF 10 | which sudo > /dev/null 2>&1 11 | if [ $? == 0 ]; then 12 | SUDO=ON 13 | fi 14 | 15 | # fix module.go 16 | for GOBPF in $(ls $GOPATH/pkg/mod/github.com/iovisor); 17 | do 18 | if [ "$SUDO" == "ON" ]; then 19 | sudo sed -i 's/C.bpf_attach_uprobe(C.int(fd), attachType, evNameCS, binaryPathCS, (C.uint64_t)(addr), (C.pid_t)(pid))/C.bpf_attach_uprobe(C.int(fd), attachType, evNameCS, binaryPathCS, (C.uint64_t)(addr), (C.pid_t)(pid), 0)/g' $GOPATH/pkg/mod/github.com/iovisor/$GOBPF/bcc/module.go 20 | else 21 | sed -i 's/C.bpf_attach_uprobe(C.int(fd), attachType, evNameCS, binaryPathCS, (C.uint64_t)(addr), (C.pid_t)(pid))/C.bpf_attach_uprobe(C.int(fd), attachType, evNameCS, binaryPathCS, (C.uint64_t)(addr), (C.pid_t)(pid), 0)/g' $GOPATH/pkg/mod/github.com/iovisor/$GOBPF/bcc/module.go 22 | fi 23 | done 24 | -------------------------------------------------------------------------------- /src/service/protobuf/Makefile: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | # Copyright 2021 Authors of KubeArmor 3 | 4 | CURDIR=$(shell pwd) 5 | 6 | .PHONY: build 7 | build: 8 | #cd $(CURDIR); go get . 9 | cd $(CURDIR); protoc --proto_path=. --go_opt=paths=source_relative --go_out=plugins=grpc:. kvm.proto clihandler.proto 10 | 11 | .PHONY: clean 12 | clean: 13 | cd $(CURDIR); find . -name go.sum | xargs -I {} rm -f {} 14 | -------------------------------------------------------------------------------- /src/service/protobuf/clihandler.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package clihandler; 4 | 5 | option go_package="github.com/kubearmor/KVMService/src/service/protobuf"; 6 | 7 | message CliRequest { 8 | string KvmName = 1; 9 | } 10 | 11 | message ResponseStatus { 12 | string ScriptData = 1; 13 | string StatusMsg = 2; 14 | int32 Status = 3; 15 | } 16 | 17 | service HandleCli { 18 | rpc HandleCliRequest (CliRequest) returns (ResponseStatus); 19 | } 20 | -------------------------------------------------------------------------------- /src/service/protobuf/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/kubearmor/KVMService/src/service/protobuf 2 | 3 | go 1.17 4 | 5 | require ( 6 | google.golang.org/grpc v1.41.0 7 | google.golang.org/protobuf v1.27.1 8 | ) 9 | 10 | require ( 11 | github.com/golang/protobuf v1.5.0 // indirect 12 | golang.org/x/net v0.0.0-20200822124328-c89045814202 // indirect 13 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd // indirect 14 | golang.org/x/text v0.3.0 // indirect 15 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect 16 | ) 17 | -------------------------------------------------------------------------------- /src/service/protobuf/kvm.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package kvm; 4 | 5 | option go_package="github.com/kubearmor/KVMService/src/service/protobuf"; 6 | 7 | message agentIdentity { 8 | string identity = 1; 9 | } 10 | 11 | message status { 12 | int32 status = 1; 13 | } 14 | 15 | message policyData { 16 | bytes policyData = 1; 17 | } 18 | 19 | service KVM { 20 | rpc registerAgentIdentity (agentIdentity) returns (status); 21 | rpc sendPolicy (stream status) returns (stream policyData); 22 | } 23 | -------------------------------------------------------------------------------- /src/service/server/clihandler.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "context" 5 | "log" 6 | 7 | ct "github.com/kubearmor/KVMService/src/constants" 8 | kg "github.com/kubearmor/KVMService/src/log" 9 | gs "github.com/kubearmor/KVMService/src/service/genscript" 10 | pb "github.com/kubearmor/KVMService/src/service/protobuf" 11 | ) 12 | 13 | // Variables / Struct 14 | type CLIServer struct { 15 | pb.HandleCliServer 16 | } 17 | 18 | func (c *CLIServer) HandleCliRequest(ctx context.Context, request *pb.CliRequest) (*pb.ResponseStatus, error) { 19 | kg.Printf("Recieved the request KVMName:%s\n", request.KvmName) 20 | kvPair, err := EtcdClient.EtcdGet(context.Background(), ct.KvmOprEWNameToIdentity+request.KvmName) 21 | if err != nil { 22 | log.Fatal(err) 23 | return &pb.ResponseStatus{ScriptData: "", StatusMsg: "Error: DB reading failed", Status: -1}, err 24 | } 25 | 26 | if len(kvPair[ct.KvmOprEWNameToIdentity+request.KvmName]) == 0 { 27 | return &pb.ResponseStatus{ScriptData: "", StatusMsg: "Error: KVM Name is not present in DB", Status: -1}, nil 28 | } 29 | 30 | kg.Printf("Handling the CLI request for Identity '%s'\n", kvPair[ct.KvmOprEWNameToIdentity+request.KvmName]) 31 | 32 | scriptData := gs.GenerateEWInstallationScript(request.KvmName, kvPair[ct.KvmOprEWNameToIdentity+request.KvmName]) 33 | return &pb.ResponseStatus{ScriptData: scriptData, StatusMsg: "Success", Status: 0}, nil 34 | } 35 | -------------------------------------------------------------------------------- /src/service/server/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/kubearmor/KVMService/src/service/server 2 | 3 | go 1.17 4 | 5 | replace ( 6 | github.com/kubearmor/KVMService/src/common => ../../common 7 | github.com/kubearmor/KVMService/src/constants => ../../constants 8 | github.com/kubearmor/KVMService/src/etcd => ../../etcd 9 | github.com/kubearmor/KVMService/src/log => ../../log 10 | github.com/kubearmor/KVMService/src/service/genscript => ../genscript 11 | github.com/kubearmor/KVMService/src/service/protobuf => ../protobuf 12 | github.com/kubearmor/KVMService/src/types => ../../types 13 | ) 14 | 15 | require ( 16 | github.com/kubearmor/KVMService/src/constants v0.0.0-00010101000000-000000000000 17 | github.com/kubearmor/KVMService/src/etcd v0.0.0-00010101000000-000000000000 18 | github.com/kubearmor/KVMService/src/log v0.0.0-00010101000000-000000000000 19 | github.com/kubearmor/KVMService/src/service/genscript v0.0.0-00010101000000-000000000000 20 | github.com/kubearmor/KVMService/src/service/protobuf v0.0.0-00010101000000-000000000000 21 | github.com/kubearmor/KVMService/src/types v0.0.0-00010101000000-000000000000 22 | google.golang.org/grpc v1.42.0 23 | ) 24 | 25 | require ( 26 | github.com/coreos/go-semver v0.3.0 // indirect 27 | github.com/coreos/go-systemd/v22 v22.3.2 // indirect 28 | github.com/davecgh/go-spew v1.1.1 // indirect 29 | github.com/go-logr/logr v0.4.0 // indirect 30 | github.com/gogo/protobuf v1.3.2 // indirect 31 | github.com/golang/protobuf v1.5.2 // indirect 32 | github.com/google/go-cmp v0.5.5 // indirect 33 | github.com/google/gofuzz v1.1.0 // indirect 34 | github.com/googleapis/gnostic v0.5.5 // indirect 35 | github.com/json-iterator/go v1.1.11 // indirect 36 | github.com/kubearmor/KVMService/src/common v0.0.0-00010101000000-000000000000 // indirect 37 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 38 | github.com/modern-go/reflect2 v1.0.1 // indirect 39 | go.etcd.io/etcd/api/v3 v3.5.1 // indirect 40 | go.etcd.io/etcd/client/pkg/v3 v3.5.1 // indirect 41 | go.etcd.io/etcd/client/v3 v3.5.1 // indirect 42 | go.uber.org/atomic v1.7.0 // indirect 43 | go.uber.org/multierr v1.6.0 // indirect 44 | go.uber.org/zap v1.19.1 // indirect 45 | golang.org/x/net v0.0.0-20210520170846-37e1c6afe023 // indirect 46 | golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect 47 | golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 // indirect 48 | golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d // indirect 49 | golang.org/x/text v0.3.6 // indirect 50 | golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect 51 | google.golang.org/appengine v1.6.5 // indirect 52 | google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c // indirect 53 | google.golang.org/protobuf v1.27.1 // indirect 54 | gopkg.in/inf.v0 v0.9.1 // indirect 55 | gopkg.in/yaml.v2 v2.4.0 // indirect 56 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect 57 | k8s.io/api v0.22.4 // indirect 58 | k8s.io/apimachinery v0.22.4 // indirect 59 | k8s.io/client-go v0.22.4 // indirect 60 | k8s.io/klog/v2 v2.9.0 // indirect 61 | k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a // indirect 62 | sigs.k8s.io/structured-merge-diff/v4 v4.1.2 // indirect 63 | sigs.k8s.io/yaml v1.2.0 // indirect 64 | ) 65 | -------------------------------------------------------------------------------- /src/service/server/kvmserver.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "log" 7 | "strconv" 8 | "strings" 9 | 10 | ct "github.com/kubearmor/KVMService/src/constants" 11 | kg "github.com/kubearmor/KVMService/src/log" 12 | pb "github.com/kubearmor/KVMService/src/service/protobuf" 13 | tp "github.com/kubearmor/KVMService/src/types" 14 | "google.golang.org/grpc/metadata" 15 | ) 16 | 17 | type KVMServer struct { 18 | pb.UnimplementedKVMServer 19 | } 20 | 21 | func GetIdentityFromContext(ctx context.Context) uint16 { 22 | var values []string 23 | var token string 24 | 25 | md, ok := metadata.FromIncomingContext(ctx) 26 | if ok { 27 | values = md.Get("identity") 28 | if len(values) > 0 { 29 | token = values[0] 30 | } 31 | } 32 | identity, _ := strconv.Atoi(token) 33 | 34 | return uint16(identity) 35 | } 36 | 37 | func UpdateETCDLabelToIdentitiesMaps(identity uint16) { 38 | 39 | err := EtcdClient.EtcdDelete(context.Background(), ct.KvmSvcIdentitiToPodIps+strconv.Itoa(int(identity))) 40 | if err != nil { 41 | kg.Err(err.Error()) 42 | return 43 | } 44 | 45 | labelKV, err := EtcdClient.EtcdGet(context.Background(), ct.KvmOprIdentityToLabel+strconv.Itoa(int(identity))) 46 | if err != nil { 47 | log.Fatal(err) 48 | return 49 | } 50 | label := labelKV[ct.KvmOprIdentityToLabel+strconv.Itoa(int(identity))] 51 | 52 | data, err := EtcdClient.EtcdGetRaw(context.Background(), ct.KvmOprLabelToIdentities+label) 53 | if err != nil { 54 | log.Fatal(err) 55 | return 56 | } 57 | 58 | var arr []uint16 59 | for _, ev := range data.Kvs { 60 | err := json.Unmarshal(ev.Value, &arr) 61 | if err != nil { 62 | log.Fatal(err) 63 | return 64 | } 65 | kg.Printf("Removing the identity(%d) from the labels map of ETCD arr:%+v", identity, arr) 66 | for index, value := range arr { 67 | if identity == value { 68 | arr[index] = arr[len(arr)-1] 69 | arr[len(arr)-1] = 0 70 | arr = arr[:len(arr)-1] 71 | } 72 | } 73 | kg.Printf("After removing the identity(%d) from the labels map of ETCD arr:%+v", identity, arr) 74 | mapStr, _ := json.Marshal(arr) 75 | err = EtcdClient.EtcdPut(context.Background(), ct.KvmOprLabelToIdentities+label, string(mapStr)) 76 | if err != nil { 77 | log.Fatal(err) 78 | } 79 | } 80 | } 81 | 82 | func (s *KVMServer) SendPolicy(stream pb.KVM_SendPolicyServer) error { 83 | var policy pb.PolicyData 84 | var loop bool 85 | loop = true 86 | 87 | kg.Print("Started Policy Streamer\n") 88 | 89 | go func() { 90 | for loop { 91 | // select { 92 | // case <-stream.Context().Done(): 93 | <-stream.Context().Done() 94 | closeEvent := tp.K8sKubeArmorHostPolicyEventWithIdentity{} 95 | closeEvent.Identity = GetIdentityFromContext(stream.Context()) 96 | closeEvent.CloseConnection = true 97 | kg.Errf("Closing client connections for identity %d\n", closeEvent.Identity) 98 | UpdateETCDLabelToIdentitiesMaps(GetIdentityFromContext(stream.Context())) 99 | loop = false 100 | PolicyChan <- closeEvent 101 | //} 102 | } 103 | }() 104 | 105 | for { 106 | select { 107 | case event := <-PolicyChan: 108 | if event.Identity == GetIdentityFromContext(stream.Context()) { 109 | if !event.CloseConnection { 110 | policyBytes, err := json.Marshal(&event.Event) 111 | if err != nil { 112 | kg.Print("Failed to marshall data") 113 | } else { 114 | policy.PolicyData = policyBytes 115 | err := stream.Send(&policy) 116 | if err != nil { 117 | kg.Print("Failed to send") 118 | } 119 | response, err := stream.Recv() 120 | if err != nil { 121 | kg.Print("Failed to recv") 122 | } 123 | kg.Printf("Policy Enforcement status in host :%d", response.Status) 124 | } 125 | } else { 126 | kg.Printf("Context is %d", GetIdentityFromContext(stream.Context())) 127 | kg.Print("Closing the connection") 128 | return nil 129 | } 130 | } 131 | default: 132 | continue 133 | } 134 | } 135 | } 136 | 137 | func IsIdentityServing(identity string) int { 138 | kvPair, err := EtcdClient.EtcdGet(context.Background(), ct.KvmSvcIdentitiToPodIps+identity) 139 | if err != nil { 140 | log.Fatal(err) 141 | return 0 142 | } 143 | 144 | if len(kvPair) > 0 { 145 | kg.Printf("This Identity is already served by this podIP:%s", kvPair[ct.KvmSvcIdentitiToPodIps+identity]) 146 | return 0 147 | } 148 | 149 | etcdLabels, err := EtcdClient.EtcdGet(context.Background(), ct.KvmOprIdentityToLabel) 150 | if err != nil { 151 | log.Fatal(err) 152 | } 153 | for key, value := range etcdLabels { 154 | s := strings.Split(key, "/") 155 | id := s[len(s)-1] 156 | if id == identity { 157 | kg.Printf("Validated the identity from the etcd DB identity:%s is unique for label:%s", identity, value) 158 | return 1 159 | } 160 | } 161 | kg.Printf("Recieved the invalid identity:%s", identity) 162 | return 0 163 | } 164 | 165 | func (s *KVMServer) RegisterAgentIdentity(ctx context.Context, in *pb.AgentIdentity) (*pb.Status, error) { 166 | kg.Print("Recieved the connection from the identity") 167 | var identity uint16 168 | 169 | if IsIdentityServing(in.Identity) == 0 { 170 | kg.Print("Connection refused due to already busy or invalid identity") 171 | return &pb.Status{Status: -1}, nil 172 | } 173 | 174 | value, _ := strconv.Atoi(in.Identity) 175 | identity = uint16(value) 176 | kg.Printf("New connection recieved RegisterAgentIdentity: %v podIp: %v", identity, podIp) 177 | 178 | err := EtcdClient.EtcdPutWithTTL(context.Background(), ct.KvmSvcIdentitiToPodIps+in.Identity, podIp) 179 | if err != nil { 180 | kg.Err(err.Error()) 181 | return &pb.Status{Status: -1}, err 182 | } 183 | 184 | return &pb.Status{Status: 0}, nil 185 | } 186 | -------------------------------------------------------------------------------- /src/service/server/server.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "net" 5 | 6 | etcd "github.com/kubearmor/KVMService/src/etcd" 7 | kg "github.com/kubearmor/KVMService/src/log" 8 | pb "github.com/kubearmor/KVMService/src/service/protobuf" 9 | tp "github.com/kubearmor/KVMService/src/types" 10 | "google.golang.org/grpc" 11 | ) 12 | 13 | var ( 14 | PolicyChan chan tp.K8sKubeArmorHostPolicyEventWithIdentity 15 | ClusterIp string 16 | Clusterport string 17 | podIp string 18 | EtcdClient *etcd.EtcdClient 19 | ) 20 | 21 | // Variables / Struct 22 | type Server struct { 23 | podIp string 24 | port string 25 | EtcdClient *etcd.EtcdClient 26 | } 27 | 28 | func NewServerInit(ipAddress, ClusterIpAddress, portVal string, Etcd *etcd.EtcdClient) *Server { 29 | kg.Printf("Initiliazing the KVMServer => podip:%v clusterIP:%v clusterPort:%v", ipAddress, ClusterIpAddress, portVal) 30 | podIp = ipAddress 31 | Clusterport = portVal 32 | EtcdClient = Etcd 33 | ClusterIp = ClusterIpAddress 34 | return &Server{podIp: ipAddress, port: portVal, EtcdClient: EtcdClient} 35 | } 36 | 37 | func (s *Server) InitServer() { 38 | // TCP connection - Listen on port specified in input 39 | PolicyChan = make(chan tp.K8sKubeArmorHostPolicyEventWithIdentity) 40 | tcpConn, err := net.Listen("tcp", ":"+s.port) 41 | if err != nil { 42 | kg.Printf("Error listening on port %s", s.port) 43 | } else { 44 | kg.Printf("Successfully KVMServer Listening on port %s", s.port) 45 | } 46 | 47 | // Start gRPC server and register for protobuf 48 | gRPCServer := grpc.NewServer() 49 | if gRPCServer == nil { 50 | kg.Err("Failed to serve gRPCServer is null") 51 | } 52 | 53 | // Register KVM Server 54 | pb.RegisterKVMServer(gRPCServer, &KVMServer{}) 55 | 56 | // Register CLIHandler Server 57 | pb.RegisterHandleCliServer(gRPCServer, &CLIServer{}) 58 | 59 | err = gRPCServer.Serve(tcpConn) 60 | if err != nil { 61 | kg.Err("Failed to serve") 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/types/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/kubearmor/KVMService/src/types 2 | 3 | go 1.17 4 | 5 | require ( 6 | k8s.io/api v0.22.3 7 | k8s.io/apimachinery v0.22.3 8 | ) 9 | 10 | require ( 11 | github.com/go-logr/logr v0.4.0 // indirect 12 | github.com/gogo/protobuf v1.3.2 // indirect 13 | github.com/google/go-cmp v0.5.5 // indirect 14 | github.com/google/gofuzz v1.1.0 // indirect 15 | github.com/json-iterator/go v1.1.11 // indirect 16 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 17 | github.com/modern-go/reflect2 v1.0.1 // indirect 18 | golang.org/x/net v0.0.0-20210520170846-37e1c6afe023 // indirect 19 | golang.org/x/text v0.3.6 // indirect 20 | gopkg.in/inf.v0 v0.9.1 // indirect 21 | gopkg.in/yaml.v2 v2.4.0 // indirect 22 | k8s.io/klog/v2 v2.9.0 // indirect 23 | sigs.k8s.io/structured-merge-diff/v4 v4.1.2 // indirect 24 | ) 25 | --------------------------------------------------------------------------------