An ongoing document on terraform clean practices I follow.

Type 1: Ingress defined inside the same resource as security group.

resource "aws_security_group" "sample-sg" {
  name = "sample-sg"
  vpc_id = "${aws_vpc.default.id}"

  ingress {
    protocol    = "tcp"
    from_port   = 443
    to_port     = 443
    cidr_blocks = ["0.0.0.0/0"]
  }
}

type 2: Rule is a different resource

resource "aws_security_group" "sample-sg" {
  name = "sample-sg"
  vpc_id = "${aws_vpc.default.id}"
}

resource "aws_security_group_rule" "https_allow" {
  type            = "ingress"
  from_port       = 443
  to_port         = 443
  protocol        = "tcp"
  cidr_blocks = 0.0.0.0/0
  security_group_id = "${aws_security_group.sample-sg.id}"
}

I prefer type 2 for reuse of rule https_allow in other security groups.